Skip to content

Commit db97306

Browse files
committed
feat: check for conflicting ACP and state persistence flags
1 parent 410e29b commit db97306

2 files changed

Lines changed: 38 additions & 27 deletions

File tree

cmd/server/server.go

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
135135
}
136136
}
137137

138+
experimentalACP := viper.GetBool(FlagExperimentalACP)
139+
140+
if experimentalACP && (saveState || loadState) {
141+
return xerrors.Errorf("ACP mode doesn't support state persistence")
142+
}
143+
138144
pidFile := viper.GetString(FlagPidFile)
139145

140146
// Write PID file if configured
@@ -146,7 +152,6 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
146152
}
147153

148154
printOpenAPI := viper.GetBool(FlagPrintOpenAPI)
149-
experimentalACP := viper.GetBool(FlagExperimentalACP)
150155

151156
if printOpenAPI && experimentalACP {
152157
return xerrors.Errorf("flags --%s and --%s are mutually exclusive", FlagPrintOpenAPI, FlagExperimentalACP)
@@ -222,17 +227,17 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
222227
// Monitor process exit
223228
processExitCh := make(chan error, 1)
224229
if process != nil {
225-
go func() {
226-
defer close(processExitCh)
227-
defer gracefulCancel()
228-
if err := process.Wait(); err != nil {
229-
if errors.Is(err, termexec.ErrNonZeroExitCode) {
230-
processExitCh <- xerrors.Errorf("========\n%s\n========\n: %w", strings.TrimSpace(process.ReadScreen()), err)
231-
} else {
232-
processExitCh <- xerrors.Errorf("failed to wait for process: %w", err)
230+
go func() {
231+
defer close(processExitCh)
232+
defer gracefulCancel()
233+
if err := process.Wait(); err != nil {
234+
if errors.Is(err, termexec.ErrNonZeroExitCode) {
235+
processExitCh <- xerrors.Errorf("========\n%s\n========\n: %w", strings.TrimSpace(process.ReadScreen()), err)
236+
} else {
237+
processExitCh <- xerrors.Errorf("failed to wait for process: %w", err)
238+
}
233239
}
234-
}
235-
}()
240+
}()
236241
}
237242
if acpResult != nil {
238243
go func() {
@@ -362,20 +367,20 @@ type flagSpec struct {
362367
}
363368

364369
const (
365-
FlagType = "type"
366-
FlagPort = "port"
367-
FlagPrintOpenAPI = "print-openapi"
368-
FlagChatBasePath = "chat-base-path"
369-
FlagTermWidth = "term-width"
370-
FlagTermHeight = "term-height"
371-
FlagAllowedHosts = "allowed-hosts"
372-
FlagAllowedOrigins = "allowed-origins"
373-
FlagExit = "exit"
374-
FlagInitialPrompt = "initial-prompt"
375-
FlagStateFile = "state-file"
376-
FlagLoadState = "load-state"
377-
FlagSaveState = "save-state"
378-
FlagPidFile = "pid-file"
370+
FlagType = "type"
371+
FlagPort = "port"
372+
FlagPrintOpenAPI = "print-openapi"
373+
FlagChatBasePath = "chat-base-path"
374+
FlagTermWidth = "term-width"
375+
FlagTermHeight = "term-height"
376+
FlagAllowedHosts = "allowed-hosts"
377+
FlagAllowedOrigins = "allowed-origins"
378+
FlagExit = "exit"
379+
FlagInitialPrompt = "initial-prompt"
380+
FlagStateFile = "state-file"
381+
FlagLoadState = "load-state"
382+
FlagSaveState = "save-state"
383+
FlagPidFile = "pid-file"
379384
FlagExperimentalACP = "experimental-acp"
380385
)
381386

x/acpio/acp_conversation.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
st "github.com/coder/agentapi/lib/screentracker"
1212
"github.com/coder/quartz"
13+
"golang.org/x/xerrors"
1314
)
1415

1516
// Compile-time assertion that ACPConversation implements st.Conversation
@@ -31,9 +32,9 @@ type ACPConversation struct {
3132
cancel context.CancelFunc
3233
agentIO ChunkableAgentIO
3334
messages []st.ConversationMessage
34-
nextID int // monotonically increasing message ID
35+
nextID int // monotonically increasing message ID
3536
prompting bool // true while agent is processing
36-
chunkReceived chan struct{} // signals that handleChunk has accumulated a chunk
37+
chunkReceived chan struct{} // signals that handleChunk has accumulated a chunk
3738
streamingResponse strings.Builder
3839
logger *slog.Logger
3940
emitter st.Emitter
@@ -47,6 +48,7 @@ type noopEmitter struct{}
4748
func (noopEmitter) EmitMessages([]st.ConversationMessage) {}
4849
func (noopEmitter) EmitStatus(st.ConversationStatus) {}
4950
func (noopEmitter) EmitScreen(string) {}
51+
func (noopEmitter) EmitError(_ string, _ st.ErrorLevel) {}
5052

5153
// NewACPConversation creates a new ACPConversation.
5254
// If emitter is provided, it will receive events when messages/status/screen change.
@@ -284,3 +286,7 @@ func (c *ACPConversation) executePrompt(messageParts []st.MessagePart) error {
284286
c.logger.Debug("ACPConversation message complete", "responseLen", len(response))
285287
return nil
286288
}
289+
290+
func (c *ACPConversation) SaveState() error {
291+
return xerrors.Errorf("ACP mode doesn't support state persistence")
292+
}

0 commit comments

Comments
 (0)