Skip to content

Commit 12f2c41

Browse files
authored
Merge branch 'main' into feat-file-upload
2 parents 686b61d + c5679c4 commit 12f2c41

File tree

9 files changed

+36
-22
lines changed

9 files changed

+36
-22
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v0.9.0
4+
5+
### Features
6+
- Add support for initial prompt via `-I` flag
7+
38
## v0.8.0
49

510
### Features

chat/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,5 @@
4848
"start": "next start",
4949
"storybook": "storybook dev -p 6006"
5050
},
51-
"version": "0.8.0"
51+
"version": "0.9.0"
5252
}

chat/src/components/message-list.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ interface MessageListProps {
2020

2121
export default function MessageList({ messages }: MessageListProps) {
2222
const scrollAreaRef = useRef<HTMLDivElement>(null);
23-
// Avoid the message list to change its height all the time. It causes some
24-
// flickering in the screen because some messages, as the ones displaying
25-
// progress statuses, are changing the content(the number of lines) and size
26-
// constantily. To minimize it, we keep track of the biggest scroll height of
27-
// the content, and use that as the min height of the scroll area.
28-
const contentMinHeight = useRef(0);
2923

3024
// Track if user is at bottom - default to true for initial scroll
3125
const isAtBottomRef = useRef(true);
@@ -67,11 +61,6 @@ export default function MessageList({ messages }: MessageListProps) {
6761
const isNewUserMessage =
6862
messages.length > 0 && messages[messages.length - 1].role === "user";
6963

70-
// Update content min height if needed
71-
if (currentScrollHeight > contentMinHeight.current) {
72-
contentMinHeight.current = currentScrollHeight;
73-
}
74-
7564
// Auto-scroll only if:
7665
// 1. It's the first render, OR
7766
// 2. There's new content AND user was at the bottom, OR
@@ -104,9 +93,7 @@ export default function MessageList({ messages }: MessageListProps) {
10493
return (
10594
<div className="overflow-y-auto flex-1" ref={scrollAreaRef}>
10695
<div
107-
className="p-4 flex flex-col gap-4 max-w-4xl mx-auto"
108-
style={{ minHeight: contentMinHeight.current }}
109-
>
96+
className="p-4 flex flex-col gap-4 max-w-4xl mx-auto transition-all duration-300 ease-in-out min-h-0">
11097
{messages.map((message) => (
11198
<div
11299
key={message.id ?? "draft"}

cmd/server/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
112112
ChatBasePath: viper.GetString(FlagChatBasePath),
113113
AllowedHosts: viper.GetStringSlice(FlagAllowedHosts),
114114
AllowedOrigins: viper.GetStringSlice(FlagAllowedOrigins),
115+
InitialPrompt: viper.GetString(FlagInitialPrompt),
115116
})
116117
if err != nil {
117118
return xerrors.Errorf("failed to create server: %w", err)
@@ -174,6 +175,7 @@ const (
174175
FlagAllowedHosts = "allowed-hosts"
175176
FlagAllowedOrigins = "allowed-origins"
176177
FlagExit = "exit"
178+
FlagInitialPrompt = "initial-prompt"
177179
)
178180

179181
func CreateServerCmd() *cobra.Command {
@@ -211,6 +213,7 @@ func CreateServerCmd() *cobra.Command {
211213
{FlagAllowedHosts, "a", []string{"localhost", "127.0.0.1", "[::1]"}, "HTTP allowed hosts (hostnames only, no ports). Use '*' for all, comma-separated list via flag, space-separated list via AGENTAPI_ALLOWED_HOSTS env var", "stringSlice"},
212214
// localhost:3284 is the default origin when you open the chat interface in your browser. localhost:3000 and 3001 are used during development.
213215
{FlagAllowedOrigins, "o", []string{"http://localhost:3284", "http://localhost:3000", "http://localhost:3001"}, "HTTP allowed origins. Use '*' for all, comma-separated list via flag, space-separated list via AGENTAPI_ALLOWED_ORIGINS env var", "stringSlice"},
216+
{FlagInitialPrompt, "I", "", "Initial prompt for the agent (recommended only if the agent doesn't support initial prompt in interaction mode)", "string"},
214217
}
215218

216219
for _, spec := range flagSpecs {

internal/version/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
package version
44

5-
var Version = "0.8.0"
5+
var Version = "0.9.0"

lib/httpapi/server.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ type ServerConfig struct {
101101
ChatBasePath string
102102
AllowedHosts []string
103103
AllowedOrigins []string
104+
InitialPrompt string
104105
}
105106

106107
// Validate allowed hosts don't contain whitespace, commas, schemes, or ports.
@@ -236,7 +237,7 @@ func NewServer(ctx context.Context, config ServerConfig) (*Server, error) {
236237
SnapshotInterval: snapshotInterval,
237238
ScreenStabilityLength: 2 * time.Second,
238239
FormatMessage: formatMessage,
239-
})
240+
}, config.InitialPrompt)
240241
emitter := NewEventEmitter(1024)
241242

242243
// Create temporary directory for uploads
@@ -321,7 +322,19 @@ func (s *Server) StartSnapshotLoop(ctx context.Context) {
321322
s.conversation.StartSnapshotLoop(ctx)
322323
go func() {
323324
for {
324-
s.emitter.UpdateStatusAndEmitChanges(s.conversation.Status())
325+
currentStatus := s.conversation.Status()
326+
327+
// Send initial prompt when agent becomes stable for the first time
328+
if !s.conversation.InitialPromptSent && convertStatus(currentStatus) == AgentStatusStable {
329+
if err := s.conversation.SendMessage(FormatMessage(s.agentType, s.conversation.InitialPrompt)...); err != nil {
330+
s.logger.Error("Failed to send initial prompt", "error", err)
331+
} else {
332+
s.conversation.InitialPromptSent = true
333+
currentStatus = st.ConversationStatusChanging
334+
s.logger.Info("Initial prompt sent successfully")
335+
}
336+
}
337+
s.emitter.UpdateStatusAndEmitChanges(currentStatus)
325338
s.emitter.UpdateMessagesAndEmitChanges(s.conversation.Messages())
326339
s.emitter.UpdateScreenAndEmitChanges(s.conversation.Screen())
327340
time.Sleep(snapshotInterval)

lib/screentracker/conversation.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ type Conversation struct {
7474
messages []ConversationMessage
7575
screenBeforeLastUserMessage string
7676
lock sync.Mutex
77+
// InitialPrompt is the initial prompt passed to the agent
78+
InitialPrompt string
79+
// InitialPromptSent keeps track if the InitialPrompt has been successfully sent to the agents
80+
InitialPromptSent bool
7781
}
7882

7983
type ConversationStatus string
@@ -94,7 +98,7 @@ func getStableSnapshotsThreshold(cfg ConversationConfig) int {
9498
return threshold + 1
9599
}
96100

97-
func NewConversation(ctx context.Context, cfg ConversationConfig) *Conversation {
101+
func NewConversation(ctx context.Context, cfg ConversationConfig, initialPrompt string) *Conversation {
98102
threshold := getStableSnapshotsThreshold(cfg)
99103
c := &Conversation{
100104
cfg: cfg,
@@ -107,6 +111,8 @@ func NewConversation(ctx context.Context, cfg ConversationConfig) *Conversation
107111
Time: cfg.GetTime(),
108112
},
109113
},
114+
InitialPrompt: initialPrompt,
115+
InitialPromptSent: len(initialPrompt) == 0,
110116
}
111117
return c
112118
}

lib/screentracker/conversation_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func statusTest(t *testing.T, params statusTestParams) {
4242
if params.cfg.GetTime == nil {
4343
params.cfg.GetTime = func() time.Time { return time.Now() }
4444
}
45-
c := st.NewConversation(ctx, params.cfg)
45+
c := st.NewConversation(ctx, params.cfg, "")
4646
assert.Equal(t, st.ConversationStatusInitializing, c.Status())
4747

4848
for i, step := range params.steps {
@@ -147,7 +147,7 @@ func TestMessages(t *testing.T) {
147147
for _, opt := range opts {
148148
opt(&cfg)
149149
}
150-
return st.NewConversation(context.Background(), cfg)
150+
return st.NewConversation(context.Background(), cfg, "")
151151
}
152152

153153
t.Run("messages are copied", func(t *testing.T) {

openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@
334334
"info": {
335335
"description": "HTTP API for Claude Code, Goose, and Aider.\n\nhttps://github.com/coder/agentapi",
336336
"title": "AgentAPI",
337-
"version": "0.8.0"
337+
"version": "0.9.0"
338338
},
339339
"openapi": "3.1.0",
340340
"paths": {

0 commit comments

Comments
 (0)