Skip to content

Commit 42b7fba

Browse files
authored
Merge branch 'main' into 35C4n0r/handle-partial-tool-call
2 parents 9324e3d + c8502fb commit 42b7fba

49 files changed

Lines changed: 4373 additions & 243 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
jobs:
1717
build:
1818
name: Build Release Binaries
19-
runs-on: depot-ubuntu-22.04-4
19+
runs-on: ubuntu-latest-8-cores
2020
if: ${{ github.repository_owner == 'coder' }}
2121

2222
steps:

CHANGELOG.md

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

3+
## v0.12.1
4+
5+
### Fixes
6+
- Prevent terminal echo from being captured as agent messages
7+
- Update codex message box detection
8+
9+
## v0.12.0
10+
11+
### Features
12+
- Experimental ACP integration
13+
- Introduce state persistence
14+
15+
### Fixes
16+
- Fix pr-preview and build-release workflow errors
17+
18+
### Chore
19+
- Codebase refactor for abstraction
20+
- Go version bump to 1.24
21+
- Use coder/quartz
22+
323
## v0.11.8
424

525
### Fix

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.11.8"
51+
"version": "0.12.1"
5252
}

chat/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function RootLayout({
2929
disableTransitionOnChange
3030
>
3131
{children}
32-
<Toaster richColors />
32+
<Toaster richColors closeButton />
3333
</ThemeProvider>
3434
</body>
3535
</html>

chat/src/components/chat-provider.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ interface StatusChangeEvent {
3636
agent_type: string;
3737
}
3838

39+
interface ErrorEventData {
40+
message: string;
41+
level: string;
42+
time: string;
43+
}
44+
3945
interface APIErrorDetail {
4046
location: string;
4147
message: string;
@@ -215,6 +221,25 @@ export function ChatProvider({ children }: PropsWithChildren) {
215221
setAgentType(data.agent_type === "" ? "unknown" : data.agent_type as AgentType);
216222
});
217223

224+
// Handle agent error events
225+
eventSource.addEventListener("agent_error", (event) => {
226+
const messageEvent = event as MessageEvent;
227+
try {
228+
const data: ErrorEventData = JSON.parse(messageEvent.data);
229+
230+
// Display error as toast notification that persists until manually dismissed
231+
if (data.level === "error") {
232+
toast.error(data.message, { duration: Infinity });
233+
} else if (data.level === "warning") {
234+
toast.warning(data.message, { duration: Infinity });
235+
} else {
236+
toast.info(data.message, { duration: Infinity });
237+
}
238+
} catch (e) {
239+
console.error("Failed to parse agent_error event data:", e);
240+
}
241+
});
242+
218243
// Handle connection open (server is online)
219244
eventSource.onopen = () => {
220245
// Connection is established, but we'll wait for status_change event
@@ -303,10 +328,9 @@ export function ChatProvider({ children }: PropsWithChildren) {
303328
description: message,
304329
});
305330
} finally {
331+
// Remove optimistic draft message if still present (may have been replaced by server response via SSE).
332+
setMessages((prev) => prev.filter((m) => !isDraftMessage(m)));
306333
if (type === "user") {
307-
setMessages((prevMessages) =>
308-
prevMessages.filter((m) => !isDraftMessage(m))
309-
);
310334
setLoading(false);
311335
}
312336
}

cmd/attach/attach.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,33 @@ func WriteRawInputOverHTTP(ctx context.Context, url string, msg string) error {
129129
return nil
130130
}
131131

132-
func runAttach(remoteUrl string) error {
132+
func checkACPMode(remoteURL string) (bool, error) {
133+
resp, err := http.Get(remoteURL + "/status")
134+
if err != nil {
135+
return false, xerrors.Errorf("failed to check server status: %w", err)
136+
}
137+
defer func() { _ = resp.Body.Close() }()
138+
139+
if resp.StatusCode != http.StatusOK {
140+
return false, xerrors.Errorf("unexpected %d response from server: %s", resp.StatusCode, resp.Status)
141+
}
142+
143+
var status httpapi.StatusResponse
144+
if err := json.NewDecoder(resp.Body).Decode(&status.Body); err != nil {
145+
return false, xerrors.Errorf("failed to decode server status: %w", err)
146+
}
147+
148+
return status.Body.Transport == httpapi.TransportACP, nil
149+
}
150+
151+
func runAttach(remoteURL string) error {
152+
// Check if server is running in ACP mode (attach not supported)
153+
if isACP, err := checkACPMode(remoteURL); err != nil {
154+
_, _ = fmt.Fprintf(os.Stderr, "WARN: Unable to check server: %s", err.Error())
155+
} else if isACP {
156+
return xerrors.New("attach is not yet supported in ACP mode")
157+
}
158+
133159
ctx, cancel := context.WithCancel(context.Background())
134160
defer cancel()
135161
stdin := int(os.Stdin.Fd())
@@ -152,7 +178,7 @@ func runAttach(remoteUrl string) error {
152178
readScreenErrCh := make(chan error, 1)
153179
go func() {
154180
defer close(readScreenErrCh)
155-
if err := ReadScreenOverHTTP(ctx, remoteUrl+"/internal/screen", screenCh); err != nil {
181+
if err := ReadScreenOverHTTP(ctx, remoteURL+"/internal/screen", screenCh); err != nil {
156182
if errors.Is(err, context.Canceled) {
157183
return
158184
}
@@ -175,7 +201,7 @@ func runAttach(remoteUrl string) error {
175201
if input == "\x03" {
176202
continue
177203
}
178-
if err := WriteRawInputOverHTTP(ctx, remoteUrl+"/message", input); err != nil {
204+
if err := WriteRawInputOverHTTP(ctx, remoteURL+"/message", input); err != nil {
179205
writeRawInputErrCh <- xerrors.Errorf("failed to write raw input: %w", err)
180206
return
181207
}

cmd/server/process_unix.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//go:build unix
2+
3+
package server
4+
5+
import (
6+
"errors"
7+
"os"
8+
"syscall"
9+
)
10+
11+
// isProcessRunning checks if a process with the given PID is running.
12+
func isProcessRunning(pid int) bool {
13+
process, err := os.FindProcess(pid)
14+
if err != nil {
15+
return false
16+
}
17+
err = process.Signal(syscall.Signal(0))
18+
return err == nil || errors.Is(err, syscall.EPERM)
19+
}

cmd/server/process_windows.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build windows
2+
3+
package server
4+
5+
// isProcessRunning checks if a process with the given PID is running.
6+
// On Windows, Signal(0) is not supported, so this always returns false.
7+
// PID file liveness detection is best-effort on this platform.
8+
func isProcessRunning(_ int) bool {
9+
return false
10+
}

0 commit comments

Comments
 (0)