feat: add experimental agents support (#22290)

feat: add AI chat system with agent tools and chat UI

Introduce the chatd subsystem and Agents UI for AI-powered chat
within Coder workspaces.

- Add chatd package with chat loop, message compaction, prompt
  management, and LLM provider integration (OpenAI, Anthropic)
- Add agent tools: create workspace, list/read templates, read/write/
  edit files, execute commands
- Add chat API endpoints with streaming, message editing, and
  durable reconnection
- Add database schema and migrations for chats, chat messages, chat
  providers, and chat model configs
- Add RBAC policies and dbauthz enforcement for chat resources
- Add Agents UI pages with conversation timeline, queued messages
  list, diff viewer, and model configuration panel
- Add comprehensive test coverage including coderd integration tests,
  chatd unit tests, and Storybook stories
- Gate feature behind experiments flag

---------

Co-authored-by: Cian Johnston <cian@coder.com>
Co-authored-by: Danielle Maywood <danielle@themaywoods.com>
Co-authored-by: Jeremy Ruppel <jeremy@coder.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle Carberry
2026-02-27 11:50:56 -05:00
committed by GitHub
parent 67da4e8b56
commit edee917d88
201 changed files with 44828 additions and 1859 deletions
+11
View File
@@ -72,6 +72,16 @@ var (
Type: "boundary_usage",
}
// ResourceChat
// Valid Actions
// - "ActionCreate" :: create a new chat
// - "ActionDelete" :: delete a chat
// - "ActionRead" :: read chat messages and metadata
// - "ActionUpdate" :: update chat title or settings
ResourceChat = Object{
Type: "chat",
}
// ResourceConnectionLog
// Valid Actions
// - "ActionRead" :: read connection logs
@@ -429,6 +439,7 @@ func AllResources() []Objecter {
ResourceAssignRole,
ResourceAuditLog,
ResourceBoundaryUsage,
ResourceChat,
ResourceConnectionLog,
ResourceCryptoKey,
ResourceDebugInfo,
+10
View File
@@ -77,6 +77,13 @@ var taskActions = map[Action]ActionDefinition{
ActionDelete: "delete task",
}
var chatActions = map[Action]ActionDefinition{
ActionCreate: "create a new chat",
ActionRead: "read chat messages and metadata",
ActionUpdate: "update chat title or settings",
ActionDelete: "delete a chat",
}
// RBACPermissions is indexed by the type
var RBACPermissions = map[string]PermissionDefinition{
// Wildcard is every object, and the action "*" provides all actions.
@@ -103,6 +110,9 @@ var RBACPermissions = map[string]PermissionDefinition{
"task": {
Actions: taskActions,
},
"chat": {
Actions: chatActions,
},
// Dormant workspaces have the same perms as workspaces.
"workspace_dormant": {
Actions: workspaceActions,
+14
View File
@@ -1030,6 +1030,20 @@ func TestRolePermissions(t *testing.T) {
false: {owner, setOtherOrg, setOrgNotMe, memberMe, templateAdmin, userAdmin},
},
},
{
Name: "ChatUsage",
Actions: []policy.Action{policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
Resource: rbac.ResourceChat.WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, memberMe},
false: {
orgAdmin, otherOrgAdmin,
orgAuditor, otherOrgAuditor,
templateAdmin, orgTemplateAdmin, otherOrgTemplateAdmin,
userAdmin, orgUserAdmin, otherOrgUserAdmin,
},
},
},
}
// We expect every permission to be tested above.
+12
View File
@@ -28,6 +28,10 @@ const (
ScopeBoundaryUsageDelete ScopeName = "boundary_usage:delete"
ScopeBoundaryUsageRead ScopeName = "boundary_usage:read"
ScopeBoundaryUsageUpdate ScopeName = "boundary_usage:update"
ScopeChatCreate ScopeName = "chat:create"
ScopeChatDelete ScopeName = "chat:delete"
ScopeChatRead ScopeName = "chat:read"
ScopeChatUpdate ScopeName = "chat:update"
ScopeConnectionLogRead ScopeName = "connection_log:read"
ScopeConnectionLogUpdate ScopeName = "connection_log:update"
ScopeCryptoKeyCreate ScopeName = "crypto_key:create"
@@ -188,6 +192,10 @@ func (e ScopeName) Valid() bool {
ScopeBoundaryUsageDelete,
ScopeBoundaryUsageRead,
ScopeBoundaryUsageUpdate,
ScopeChatCreate,
ScopeChatDelete,
ScopeChatRead,
ScopeChatUpdate,
ScopeConnectionLogRead,
ScopeConnectionLogUpdate,
ScopeCryptoKeyCreate,
@@ -349,6 +357,10 @@ func AllScopeNameValues() []ScopeName {
ScopeBoundaryUsageDelete,
ScopeBoundaryUsageRead,
ScopeBoundaryUsageUpdate,
ScopeChatCreate,
ScopeChatDelete,
ScopeChatRead,
ScopeChatUpdate,
ScopeConnectionLogRead,
ScopeConnectionLogUpdate,
ScopeCryptoKeyCreate,