mirror of
https://github.com/coder/coder.git
synced 2026-06-03 04:58:23 +00:00
e57525002c
Remove the `ExperimentAgents` feature flag so the Agents feature is always available without requiring `--experiments=agents`. The feature is now in beta. Existing deployments that still pass `--experiments=agents` will get a harmless "ignoring unknown experiment" warning on startup. ### Changes **Backend:** - Remove `RequireExperimentWithDevBypass` middleware from chat and MCP server routes - Always include `AgentsAccessRole` in assignable site roles (later refactored to org-scoped on main; rebase keeps that) - Always set `AgentsTabVisible = true`, then drop the entire dead `AgentsTabVisible` metadata pipeline (Go htmlState field, populateHTMLState goroutine, HTML meta tag, useEmbeddedMetadata registration, mock); no production consumer reads it. `AgentsNavItem` already gates on `permissions.createChat`. - Make `blob:` CSP `img-src` addition unconditional - Remove `ExperimentAgents` constant, `DisplayName` case, and `ExperimentsKnown` entry **CLI:** - Graduate the agents TUI from `coder exp agents` to `coder agents` (moved from `AGPLExperimental()` to `CoreSubcommands()`) - Drop the `agent` alias so it does not collide with the hidden workspace-agent command - Rename implementation files `cli/exp_agents_*.go` -> `cli/agents_*.go` and internal identifiers (`expChatsTUIModel` -> `chatsTUIModel`, `newExpChatsTUIModel` -> `newChatsTUIModel`, `setupExpAgentsBackend` -> `setupAgentsBackend`, `startExpAgentsSession` -> `startAgentsSession`, `expAgentsPtr` -> `agentsPtr`, `expAgentsSession` -> `agentsSession`, `TestExpAgents*` -> `TestAgents*`). `expClient` (the `*codersdk.ExperimentalClient` local) is kept; `coderd/exp_chats*.go` and other still-experimental `cli/exp_*.go` commands are intentionally untouched. **Frontend:** - Remove experiment check from `AgentsNavItem` - render when `canCreateChat` is true - Remove `agentsEnabled` experiment check from `WorkspacesPage`, then gate `chatsByWorkspace` on `permissions.createChat` so users without chat access don't trigger the per-page DB query (Copilot review feedback) - Add `FeatureStageBadge` (beta) next to the Coder logo in the Agents sidebar (desktop + mobile) **Docs:** - Remove experiment flag setup instructions from `early-access.md` and `getting-started.md` (and rename `early-access.md`'s "Enable Coder Agents" heading to "Set up Coder Agents", since there is no enablement step left) - Update `chats-api.md` and `getting-started.md`'s Chats API note to say "beta" instead of "experimental" - `docs/manifest.json`: drop "experimental" from the Chats API sidebar description - `make gen` regenerated `docs/reference/cli/agents.md` and the CLI index - `scripts/check_emdash.sh`: exclude `cli/testdata/*.golden` and `enterprise/cli/testdata/*.golden` from the new repo-wide emdash lint, since serpent emits emdash borders in every generated `--help` golden file **Tests:** - Remove `ExperimentAgents` setup from all test files (14 occurrences across 7 files) - Update stale "with the agents experiment" comments in `coderd/x/chatd/integration_test.go` and `coderd/mcp_test.go` <img width="1185" height="900" alt="image" src="https://github.com/user-attachments/assets/b420bc8f-41d6-42c6-abd8-ad572533d651" /> > 🤖 Generated by Coder Agents
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/testutil"
|
|
)
|
|
|
|
func TestAgentsE2E(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("EmptyStateBoot", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := testutil.Context(t, testutil.WaitLong)
|
|
client, _, _ := setupAgentsBackend(t)
|
|
session := startAgentsSession(t, ctx, client)
|
|
|
|
session.expect(ctx, "No chats yet. Press n to start a new chat.")
|
|
session.quit()
|
|
require.NoError(t, session.wait(ctx))
|
|
})
|
|
|
|
t.Run("ListAndNavigate", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := testutil.Context(t, testutil.WaitLong)
|
|
client, expClient, orgID := setupAgentsBackend(t)
|
|
|
|
_ = seedChat(t, ctx, expClient, orgID, "alpha nav seed")
|
|
_ = seedChat(t, ctx, expClient, orgID, "bravo nav seed")
|
|
_ = seedChat(t, ctx, expClient, orgID, "charlie nav seed")
|
|
|
|
session := startAgentsSession(t, ctx, client)
|
|
|
|
session.expect(ctx, "charlie nav seed")
|
|
session.expect(ctx, "enter: open")
|
|
session.enter()
|
|
session.expect(ctx, "esc")
|
|
session.esc()
|
|
session.expect(ctx, "enter: open")
|
|
session.quit()
|
|
require.NoError(t, session.wait(ctx))
|
|
})
|
|
|
|
t.Run("SearchFilter", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := testutil.Context(t, testutil.WaitLong)
|
|
client, expClient, orgID := setupAgentsBackend(t)
|
|
|
|
_ = seedChat(t, ctx, expClient, orgID, "alpha filter seed")
|
|
_ = seedChat(t, ctx, expClient, orgID, "zulu filter seed")
|
|
|
|
session := startAgentsSession(t, ctx, client)
|
|
|
|
session.expect(ctx, "alpha filter seed")
|
|
session.expect(ctx, "enter: open")
|
|
session.writeRune('/')
|
|
session.expect(ctx, "/ ")
|
|
for _, r := range "zzzznotamatch" {
|
|
session.writeRune(r)
|
|
}
|
|
session.expect(ctx, "No matches.")
|
|
session.ctrlC()
|
|
require.NoError(t, session.wait(ctx))
|
|
})
|
|
|
|
t.Run("ExistingChatHistory", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := testutil.Context(t, testutil.WaitLong)
|
|
client, expClient, orgID := setupAgentsBackend(t)
|
|
|
|
chat := seedChat(t, ctx, expClient, orgID, "direct open seed")
|
|
session := startAgentsSession(t, ctx, client, chat.ID.String())
|
|
|
|
// The initial render contains both the chat title/content
|
|
// and the status bar in a single frame. Their relative
|
|
// order in the PTY byte stream depends on async title
|
|
// generation, so matching them with separate sequential
|
|
// expects is racy. Instead, just confirm the seed text is
|
|
// visible (proving we are in the chat view), then verify
|
|
// esc navigates back to the list.
|
|
session.expect(ctx, "direct open seed")
|
|
session.esc()
|
|
session.expect(ctx, "enter: open")
|
|
session.quit()
|
|
require.NoError(t, session.wait(ctx))
|
|
})
|
|
}
|