Skip to content

Commit 9ebbdd9

Browse files
kevinelliottclaude
andcommitted
Add conversation summarization, unique agent IDs, and local event storage (v0.4.1)
Features: - Conversation Summarization: - Automatic AI-generated summaries at conversation completion - Configurable summary agent (default: Gemini) - --no-summary flag and config option to disable - --summary-agent flag to override configured agent - Summary metadata includes agent type, model, tokens, cost, duration - Summary tokens and cost factored into conversation totals - Unique Agent IDs: - Agent IDs now unique per instance: {agentType}-{index} - Supports multiple agents of same type in single conversation - AgentID included in all bridge streaming events - AgentID in conversation.started participants list - AgentID in all message.created events - Local Event Storage: - Events saved to ~/.agentpipe/events/ directory - One JSON Lines file per conversation - Non-blocking async operation Changes: - Enhanced ConversationCompletedData with SummaryMetadata struct - Added SummaryConfig to configuration - Updated EmitMessageCreated signature to include agentID - Added EventStore for local event persistence - Updated all call sites and tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9506ade commit 9ebbdd9

11 files changed

Lines changed: 566 additions & 71 deletions

File tree

CHANGELOG.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v0.4.1] - 2025-10-22
11+
12+
### Added
13+
- **Conversation Summarization**: Automatic AI-generated summaries at conversation completion
14+
- Configurable summary agent (default: Gemini, supports all agent types)
15+
- `--no-summary` flag to disable summaries
16+
- `--summary-agent` flag to override configured agent
17+
- Summary configuration in YAML config file
18+
- Summary metadata includes agent type, model, tokens, cost, and duration
19+
- Summary tokens and cost factored into conversation totals
20+
- Smart prompt design avoiding meta-commentary
21+
22+
- **Unique Agent IDs**: Enhanced agent identification for multiple agents of same type
23+
- Agent IDs now unique per instance: `{agentType}-{index}` (e.g., `claude-0`, `claude-1`)
24+
- AgentID included in all bridge streaming events
25+
- Allows tracking of multiple agents with same type in single conversation
26+
- AgentID in conversation.started participants list
27+
- AgentID in all message.created events
28+
29+
- **Event Store**: Local event persistence
30+
- Events saved to `~/.agentpipe/events/` directory
31+
- One JSON Lines file per conversation
32+
- Non-blocking async operation
33+
- Debug logging for storage errors
34+
35+
### Changed
36+
- **Bridge Events**: Enhanced ConversationCompletedData structure
37+
- Summary field now contains full SummaryMetadata (instead of plain string)
38+
- Includes summary agent type, model, tokens, cost, duration
39+
- Total tokens and cost now include summary metrics
40+
- Duration does not include summary generation time
41+
42+
- **Streaming Protocol**: Updated message event structure
43+
- EmitMessageCreated now requires agentID as first parameter
44+
- MessageCreatedData includes agent_id field
45+
- AgentParticipant includes agent_id field
46+
47+
### Fixed
48+
- Agent identification for conversations with multiple agents of same type
49+
- Cost tracking to include summary generation costs in totals
50+
- Thread-safe access to bridge emitter in orchestrator
51+
52+
## [v0.4.0] - 2025-10-21
53+
54+
### Added
55+
- **Bridge Connection Events**: Automatic connection announcement
56+
- Emit bridge.connected event on emitter initialization
57+
- System info included in connection event
58+
- Synchronous sending ensures reliability
59+
60+
- **Cancellation Detection**: Detect and report conversation interruption
61+
- Emit conversation.completed with status="interrupted" on Ctrl+C
62+
- Distinguish between normal completion and cancellation
63+
- Proper error propagation in orchestrator
64+
65+
### Changed
66+
- **Event Reliability**: Improved critical event delivery
67+
- Use synchronous SendEvent for completion and error events
68+
- Prevent truncated JSON payloads on program exit
69+
1070
## [v0.3.0] - 2025-10-21
1171

1272
### Added

README.md

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -92,33 +92,35 @@ All agents now use a **standardized interaction pattern** with structured three-
9292

9393
See [CHANGELOG.md](CHANGELOG.md) for detailed version history and release notes.
9494

95-
**Latest Release**: v0.3.0 - Real-time conversation streaming to AgentPipe Web
96-
97-
**What's New in v0.3.0**:
98-
99-
🌐 **Major New Feature - Streaming Bridge:**
100-
- **Real-Time Conversation Streaming**: Stream live conversations to AgentPipe Web for browser viewing
101-
- Four event types: conversation.started, message.created, conversation.completed, conversation.error
102-
- Non-blocking async implementation that never interrupts conversations
103-
- Rich metrics: agent participants, CLI versions, tokens, costs, duration, system info
104-
- Privacy-first: disabled by default, API keys never logged
105-
- **Bridge CLI Commands**: Easy configuration and management
106-
- `agentpipe bridge setup` - Interactive wizard
107-
- `agentpipe bridge status` - View config (with `--json` support)
108-
- `agentpipe bridge test` - Test connection
109-
- `agentpipe bridge disable` - Disable streaming
110-
- **Production Ready**: Retry logic with exponential backoff, >80% test coverage
111-
112-
⚠️ **Breaking Changes:**
113-
- Extended Agent interface with `GetCLIVersion()` method
114-
- All built-in adapters updated
115-
- Custom agent implementations must implement this new method
116-
117-
**Improvements:**
118-
- Added BridgeConfig to support streaming configuration
119-
- Thread-safe orchestrator with RWMutex for concurrent bridge access
120-
- Environment variable overrides for bridge settings
121-
95+
**Latest Release**: v0.4.1 - Conversation summarization & unique agent IDs
96+
97+
**What's New in v0.4.1**:
98+
99+
📝 **Conversation Summarization**:
100+
- **AI-Generated Summaries**: Automatic summaries at conversation completion
101+
- Configurable summary agent (default: Gemini, supports all agent types)
102+
- `--no-summary` flag to disable summaries
103+
- `--summary-agent` flag to override configured agent
104+
- Summary metadata includes agent type, model, tokens, cost, duration
105+
- Summary tokens and cost factored into conversation totals
106+
- Smart prompt design avoiding meta-commentary
107+
108+
👥 **Unique Agent IDs**:
109+
- **Enhanced Agent Identification**: Support multiple agents of the same type
110+
- Agent IDs now unique per instance: `claude-0`, `claude-1`, etc.
111+
- AgentID included in all bridge streaming events
112+
- Track individual agents in conversations with multiple agents of same type
113+
- AgentID in conversation.started participants list
114+
- AgentID in all message.created events
115+
116+
💾 **Local Event Storage**:
117+
- **Event Persistence**: Events saved to `~/.agentpipe/events/`
118+
- One JSON Lines file per conversation
119+
- Non-blocking async operation
120+
- Debug logging for storage errors
121+
122+
**Previous Release - v0.4.0**: Bridge connection events and cancellation detection
123+
**Previous Release - v0.3.0**: Real-time conversation streaming to AgentPipe Web
122124
**Previous Release - v0.2.2**: JSON output support for agents list command
123125
**Previous Release - v0.2.1**: OpenCode agent and improved package management
124126
**Previous Release - v0.2.0**: Agent upgrade command and automated version detection

cmd/run.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
"github.com/spf13/cobra"
15+
"github.com/spf13/pflag"
1516
"github.com/spf13/viper"
1617

1718
"github.com/kevinelliott/agentpipe/internal/bridge"
@@ -44,6 +45,8 @@ var (
4445
stateFile string
4546
streamEnabled bool
4647
noStream bool
48+
noSummary bool
49+
summaryAgent string
4750
)
4851

4952
var runCmd = &cobra.Command{
@@ -75,6 +78,8 @@ func init() {
7578
runCmd.Flags().StringVar(&stateFile, "state-file", "", "Specific file path to save conversation state")
7679
runCmd.Flags().BoolVar(&streamEnabled, "stream", false, "Enable streaming to AgentPipe Web for this run (overrides config)")
7780
runCmd.Flags().BoolVar(&noStream, "no-stream", false, "Disable streaming to AgentPipe Web for this run (overrides config)")
81+
runCmd.Flags().BoolVar(&noSummary, "no-summary", false, "Disable conversation summary generation (overrides config)")
82+
runCmd.Flags().StringVar(&summaryAgent, "summary-agent", "", "Agent to use for summary generation (default: gemini, overrides config)")
7883
}
7984

8085
func runConversation(cobraCmd *cobra.Command, args []string) {
@@ -140,6 +145,14 @@ func runConversation(cobraCmd *cobra.Command, args []string) {
140145
cfg.Logging.ShowMetrics = true
141146
}
142147

148+
// Apply CLI overrides for summary
149+
if noSummary {
150+
cfg.Orchestrator.Summary.Enabled = false
151+
}
152+
if summaryAgent != "" {
153+
cfg.Orchestrator.Summary.Agent = summaryAgent
154+
}
155+
143156
if err := startConversation(cobraCmd, cfg); err != nil {
144157
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
145158
os.Exit(1)
@@ -324,6 +337,7 @@ func startConversation(cmd *cobra.Command, cfg *config.Config) error {
324337
MaxTurns: cfg.Orchestrator.MaxTurns,
325338
ResponseDelay: cfg.Orchestrator.ResponseDelay,
326339
InitialPrompt: cfg.Orchestrator.InitialPrompt,
340+
Summary: cfg.Orchestrator.Summary,
327341
}
328342

329343
// Create logger if enabled
@@ -350,6 +364,10 @@ func startConversation(cmd *cobra.Command, cfg *config.Config) error {
350364
orch.SetLogger(chatLogger)
351365
}
352366

367+
// Capture command information for event tracking
368+
commandInfo := buildCommandInfo(cmd, cfg)
369+
orch.SetCommandInfo(commandInfo)
370+
353371
// Set up streaming bridge if enabled
354372
shouldStream := determineShouldStream(streamEnabled, noStream)
355373
if shouldStream {
@@ -544,3 +562,42 @@ func determineShouldStream(streamEnabled, noStream bool) bool {
544562
bridgeConfig := bridge.LoadConfig()
545563
return bridgeConfig.Enabled
546564
}
565+
566+
// buildCommandInfo constructs a CommandInfo struct from the cobra command and config
567+
func buildCommandInfo(cmd *cobra.Command, cfg *config.Config) *bridge.CommandInfo {
568+
// Build the full command string
569+
args := os.Args
570+
fullCommand := strings.Join(args, " ")
571+
572+
// Build options map with all relevant flags
573+
options := make(map[string]string)
574+
575+
// Add all flags that were explicitly set
576+
cmd.Flags().Visit(func(flag *pflag.Flag) {
577+
options[flag.Name] = flag.Value.String()
578+
})
579+
580+
// Build agent list string for readability
581+
agentList := make([]string, 0, len(cfg.Agents))
582+
for _, agent := range cfg.Agents {
583+
agentSpec := fmt.Sprintf("%s:%s", agent.Type, agent.Name)
584+
agentList = append(agentList, agentSpec)
585+
}
586+
if len(agentList) > 0 {
587+
options["agents_list"] = strings.Join(agentList, ",")
588+
}
589+
590+
return &bridge.CommandInfo{
591+
FullCommand: fullCommand,
592+
Args: args[1:], // Exclude program name
593+
Mode: cfg.Orchestrator.Mode,
594+
MaxTurns: cfg.Orchestrator.MaxTurns,
595+
InitialPrompt: cfg.Orchestrator.InitialPrompt,
596+
ConfigFile: configPath,
597+
TUIEnabled: useTUI,
598+
LoggingEnabled: cfg.Logging.Enabled,
599+
ShowMetrics: showMetrics,
600+
Timeout: int(cfg.Orchestrator.TurnTimeout.Seconds()),
601+
Options: options,
602+
}
603+
}

internal/bridge/client.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212

1313
// Client is an HTTP client for sending streaming events to AgentPipe Web
1414
type Client struct {
15-
config *Config
16-
httpClient *http.Client
15+
config *Config
16+
httpClient *http.Client
17+
suppressWarnings bool // Set to true after first failure to avoid spamming warnings
1718
}
1819

1920
// NewClient creates a new bridge client with the given configuration
@@ -23,6 +24,7 @@ func NewClient(config *Config) *Client {
2324
httpClient: &http.Client{
2425
Timeout: time.Duration(config.TimeoutMs) * time.Millisecond,
2526
},
27+
suppressWarnings: false,
2628
}
2729
}
2830

@@ -86,8 +88,16 @@ func (c *Client) SendEvent(event *Event) error {
8688
}
8789

8890
// Log error but don't fail the conversation
89-
if c.config.LogLevel == "debug" || c.config.LogLevel == "info" {
90-
fmt.Fprintf(os.Stderr, "Warning: Failed to stream event after %d attempts: %v\n",
91+
if !c.suppressWarnings {
92+
// Show a user-friendly warning only once
93+
fmt.Fprintln(os.Stderr, "\n⚠️ Bridge streaming unavailable - conversation will continue normally")
94+
fmt.Fprintln(os.Stderr, " (Events will be saved locally and can be uploaded later)")
95+
c.suppressWarnings = true
96+
}
97+
98+
// Log detailed error at debug level only
99+
if c.config.LogLevel == "debug" {
100+
fmt.Fprintf(os.Stderr, "Debug: Failed to stream event after %d attempts: %v\n",
91101
c.config.RetryAttempts+1, lastErr)
92102
}
93103

0 commit comments

Comments
 (0)