mirror of
https://github.com/coder/coder.git
synced 2026-09-21 20:51:01 +08:00
Adds the `coder exp chat context` CLI for managing workspace context sources, plus the agent-token refresh endpoint the in-workspace refresh relies on. Part of breaking the "Workspace Context Sources for Coder Agents" RFC (#26466) into small, reviewable PRs. ## What this adds **CLI (`coder exp chat context`)**, talking to the agent's local IPC socket from inside the workspace: - `list` lists the registered scan roots (built-in defaults are not shown). - `show <path>` shows a source and the resources the agent resolves from it, including failures. - `add <path>` registers a path as an additional context source. With `--chat`, it keeps the legacy one-shot behavior (read context from the path once and inject it into a single chat). - `remove <path>` unregisters a source. - `refresh [<chat>]` re-pins chat context to the agent's latest snapshot. **Agent-token refresh path** for the no-argument `refresh`: - `refresh <chat>` uses the existing user-facing `ExperimentalClient.RefreshChatContext` (already on main) and works from anywhere. - `refresh` with no argument runs inside the workspace: it re-resolves the agent's sources over the context socket (catching freshly-cloned repos and startup-script writes), then asks the agent, authenticating with its own token, to re-pin every drifted chat. No `coder login` required. - This adds `agentsdk.RefreshChatContext` and `POST /api/v2/workspaceagents/me/experimental/chat-context/refresh` (`workspaceAgentRefreshChatContext`), mirroring the existing clear endpoint's agent-token auth model. ## Testing - `go test ./cli` (`TestExpChatContextAdd`, `TestParseChatID`, `TestResolveContextSourcePath`) - `go test ./coderd/x/chatd -run TestChatContextRefreshFromAgentToken` (end-to-end: echo-provisioned agent pushes a snapshot, drifts a bound chat, the agent-token refresh re-pins it, and an agent-less chat stays untouched) - `go build ./...`, `go vet`, `golangci-lint`, `make gen` (no generated changes; experimental commands are excluded from CLI golden/doc generation) <details> <summary>Design notes</summary> This is **Split 4** of #26466. Split sequence: 1. #26558 - prompt pin consumption (merged) 2. #26570 - `codersdk` context resource types (merged) 3. #26573 - the context indicator UI (merged) 4. **This PR** - the CLI + agent-token refresh. 5. The context diff (`changes`, `ChatContextResourceChange`, the changes dialog, `buildContentPatch`) - last. Key points: - The agent-local context subsystem (`agent/agentsocket` IPC for source CRUD, snapshot, resync), the user-facing `ExperimentalClient.RefreshChatContext`, and the per-chat `chatd.RefreshChatContext` all already exist on main, so this split is the CLI surface plus the small agent-token refresh endpoint that fans out per-chat refresh across an agent's drifted chats. - `add <path>` resolves relative paths to absolute before handing them to the agent (which requires canonical paths) but preserves a leading `~` for the agent to expand against its own home. `TestResolveContextSourcePath` covers this. - The agent endpoint is annotated `@x-apidocgen {"skip": true}`, matching the other agent-token chat-context endpoints. - No diff/changes rendering is involved; that lands in the final split. </details> *This PR was created by Coder Agents on behalf of @kylecarbs.*
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/cli/clitest"
|
|
)
|
|
|
|
func TestExpChatContextAdd(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("RequiresPathArgument", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// `add` registers a context source identified by <path>, so the path
|
|
// argument is required and a bare invocation is a usage error.
|
|
inv, _ := clitest.New(t, "exp", "chat", "context", "add")
|
|
|
|
err := inv.Run()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "wanted 1 args but got 0")
|
|
})
|
|
|
|
t.Run("RequiresWorkspaceSocket", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Source registration talks to the agent over its local socket, so
|
|
// outside a workspace it fails to connect rather than silently doing
|
|
// nothing. Point at a socket path that does not exist so the dial
|
|
// fails deterministically (and never touches a real agent socket).
|
|
missingSocket := filepath.Join(t.TempDir(), "agent.sock")
|
|
inv, _ := clitest.New(t, "exp", "chat", "context", "add", t.TempDir(),
|
|
"--socket-path", missingSocket)
|
|
|
|
err := inv.Run()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "inside the workspace")
|
|
})
|
|
}
|