Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
b04c74e
fix(coderd/x/agenthooks/dispatch): reject userinfo URLs and unify the…
ibetitsmike Jul 24, 2026
ee4b47b
fix: require opt-in to trust forwarded headers in the hook handler
ibetitsmike Jul 24, 2026
668a98a
docs: correct the denied pre_tool_use note and document agenthooks ex…
ibetitsmike Jul 25, 2026
60175a3
fix(coderd/x/agenthooks/dispatch): decide over-capacity with a dedica…
ibetitsmike Jul 25, 2026
fece758
fix(coderd/x/agenthooks): keep rejected hook responses out of decisio…
ibetitsmike Jul 25, 2026
dafce78
docs(codersdk/x/agenthooks): describe hook delivery as best-effort
ibetitsmike Jul 25, 2026
cb7a158
docs(scripts/agenthooks-server): describe hook delivery as best-effort
ibetitsmike Jul 25, 2026
a5e9c7c
fix(codersdk/x/agenthooks): fail closed when a hook response cannot b…
ibetitsmike Jul 25, 2026
7eb3d6a
fix(coderd/x/agenthooks/dispatch): reject case-folded duplicate respo…
ibetitsmike Jul 25, 2026
c10f811
fix(coderd/x/agenthooks/dispatch): fold duplicate keys like encoding/…
ibetitsmike Jul 25, 2026
a934133
fix(coderd/x/agenthooks/dispatch): keep opaque override keys case-sen…
ibetitsmike Jul 25, 2026
99df0aa
docs(coderd/x/agenthooks/dispatch): reattach the duplicate-key godoc
ibetitsmike Jul 25, 2026
29e417e
fix(coderd/x/agenthooks/dispatch): align override key matching with t…
ibetitsmike Jul 25, 2026
474027d
feat(coderd): add chat suffix messages, idle failure, and content upd…
ibetitsmike Jul 23, 2026
ca70bf7
docs(coderd/x/chatd): document the FailIdle transition
ibetitsmike Jul 23, 2026
2e1f608
refactor(coderd/x/chatd/chatstate): fold FailIdle into FinishError
ibetitsmike Jul 23, 2026
40c3ad2
refactor(coderd): route message content rewrites through the chat mac…
ibetitsmike Jul 23, 2026
1241b5f
fix(coderd): scope chat message content rewrites to the locked chat
ibetitsmike Jul 23, 2026
05a9b25
docs(coderd/x/chatd): document the message content rewrite primitive
ibetitsmike Jul 23, 2026
1adbbe6
style(coderd): shorten verbose comments
ibetitsmike Jul 24, 2026
6a04447
docs(coderd/x/chatd): keep the message-rewrite contract high level
ibetitsmike Jul 25, 2026
fb07535
refactor(coderd/x/chatd/chatstate): extract shared tool-result valida…
ibetitsmike Jul 25, 2026
d3b92fb
docs(coderd/x/chatd): note suffix messages in the CompleteRequiresAct…
ibetitsmike Jul 25, 2026
26c1954
feat: wire chat lifecycle hooks into chatd
ibetitsmike Jul 23, 2026
b49821a
fix(codersdk): skip chat hook timeout validation when no hook URL is set
ibetitsmike Jul 23, 2026
300b1e2
refactor(coderd/x/chatd): use FinishError for idle hook dispatch fail…
ibetitsmike Jul 23, 2026
8f5c3b7
refactor(coderd/x/chatd): rewrite tool-call inputs through Tx.UpdateM…
ibetitsmike Jul 23, 2026
4b8738a
fix(coderd/x/chatd/chatprompt): keep tool results adjacent to their c…
ibetitsmike Jul 23, 2026
77e8f4e
refactor(coderd/x/chatd): decode hook payloads directly in tests
ibetitsmike Jul 23, 2026
b5907c4
refactor: dispatch a fresh pre_tool_use hook for every tool call
ibetitsmike Jul 23, 2026
9d4c67a
fix(coderd/x/chatd): fail the turn when subagent spawn hook dispatch …
ibetitsmike Jul 23, 2026
5a78290
refactor(coderd/x/chatd): route all lifecycle hook dispatch through o…
ibetitsmike Jul 23, 2026
92f5275
refactor(coderd/x/chatd): remove redundant hook comment
ibetitsmike Jul 24, 2026
d82370b
style(coderd/x/chatd): trim redundant hook comments
ibetitsmike Jul 24, 2026
953caff
style: remove redundant hook comments
ibetitsmike Jul 24, 2026
b7627be
refactor: adopt coderd/x/hooks import paths
ibetitsmike Jul 24, 2026
4c8c114
refactor(coderd): deduplicate chat hook error handling
ibetitsmike Jul 24, 2026
f0de694
style: use errors.AsType for hook error matching and rewrap comments
ibetitsmike Jul 24, 2026
bb9f050
fix(coderd/x/chatd): make hook tool denials self-explanatory to the m…
ibetitsmike Jul 24, 2026
f74597e
refactor(coderd/x/chatd): extract hook integration into chathooks sub…
ibetitsmike Jul 24, 2026
f085d1f
refactor: adopt codersdk/x/agenthooks import paths
ibetitsmike Jul 24, 2026
f0edb9b
chore: hide experimental chat lifecycle hook flags from server help
ibetitsmike Jul 24, 2026
2502cd3
fix(coderd/x/chatd): clarify that denied tool calls were blocked by e…
ibetitsmike Jul 24, 2026
e4ca575
fix(coderd/x/chatd/chathooks): state that denied tool calls were neve…
ibetitsmike Jul 24, 2026
62ce997
docs: align chat lifecycle hook docs with dispatch behavior
ibetitsmike Jul 24, 2026
e1c9033
fix: keep denied pre_tool_use hook context out of the client transcript
ibetitsmike Jul 24, 2026
5380806
refactor(coderd/x/chatd): reuse chatstate tool-result validation in t…
ibetitsmike Jul 25, 2026
cfba00a
docs(docs/admin/setup): frame the chat lifecycle hooks page as a how-to
ibetitsmike Jul 25, 2026
0bc4f76
fix(coderd/x/chatd): keep exclusive-tool batches rejected when a hook…
ibetitsmike Jul 25, 2026
6f08efd
docs(docs/admin/setup): describe hook delivery as best-effort
ibetitsmike Jul 25, 2026
0c5881e
docs(coderd/x/chatd): describe hook delivery as best-effort
ibetitsmike Jul 25, 2026
bbb7f90
fix(coderd/x/chatd): ignore blank stop-hook model context
ibetitsmike Jul 25, 2026
0895b4d
feat(site): surface chat lifecycle hook outcomes in the chats UI
ibetitsmike Jul 23, 2026
83fad1b
fix(site): make queued hook notices keyboard-accessible and keep prom…
ibetitsmike Jul 23, 2026
ba18878
fix(site): hide the inactive sticky message copy from assistive tech
ibetitsmike Jul 23, 2026
72a8767
fix(site): refresh chat state after promoted sends and failed edits
ibetitsmike Jul 23, 2026
1db0dbb
fix(site): drop avoidable cast in the HookNotice story
ibetitsmike Jul 23, 2026
dd429d0
fix(site): keep suppressed queued messages out of the query cache
ibetitsmike Jul 23, 2026
71aca5d
fix(site): drop manual useCallback in the compiler-managed chat store…
ibetitsmike Jul 23, 2026
0749104
fix(site): thread urlTransform through sticky user message hook notices
ibetitsmike Jul 23, 2026
879bb97
style(site/src/pages/AgentsPage): remove redundant test comments
ibetitsmike Jul 24, 2026
da1a282
test(site/src/pages/AgentsPage): cover promoted queued sends with an …
ibetitsmike Jul 24, 2026
f3de57b
fix(site): surface tool error reasons for denied and failed tool calls
ibetitsmike Jul 24, 2026
0abab9b
fix(site): surface edit_files failures and cover the execute errorTex…
ibetitsmike Jul 24, 2026
731c4a0
fix(site): align hook denial story fixtures with the external policy …
ibetitsmike Jul 24, 2026
cf7c9ac
fix(site): align hook denial fixtures with the not-executed wording
ibetitsmike Jul 24, 2026
1164044
fix(site): make dimmed timeline messages inert during edits
ibetitsmike Jul 25, 2026
399c642
fix(site/src/pages/AgentsPage): ignore stale queue snapshots after a …
ibetitsmike Jul 25, 2026
98cd3fa
test(site/src/pages/AgentsPage): scope promotion story assertions and…
ibetitsmike Jul 25, 2026
3e1edb1
style(site/src/pages/AgentsPage): tighten hook queue and story comments
ibetitsmike Jul 25, 2026
ec8631c
fix(site/src/pages/AgentsPage): keep post-send reconciliation from cl…
ibetitsmike Jul 25, 2026
d26d308
fix(site/src/pages/AgentsPage): give hook dispatch failures their own…
ibetitsmike Jul 25, 2026
fab7ea9
refactor(site/src/pages/AgentsPage): narrow the hook response guard w…
ibetitsmike Jul 25, 2026
ad1ad96
fix(site/src/pages/AgentsPage): apply the refetched status after a fa…
ibetitsmike Jul 25, 2026
9f7c512
fix(site/src/pages/AgentsPage): key the queued tail on server observa…
ibetitsmike Jul 25, 2026
7f9b717
test(site/src/pages/AgentsPage): type the status fixture without a cast
ibetitsmike Jul 25, 2026
b871933
fix(site/src/pages/AgentsPage): count repeated server status reports …
ibetitsmike Jul 25, 2026
7e28012
test(site/src/api/queries): clarify why the reconciled page order inv…
ibetitsmike Jul 25, 2026
bf86b18
fix(site/src/pages/AgentsPage): hydrate an unchanged status after a r…
ibetitsmike Jul 25, 2026
96a432d
fix(site/src/pages/AgentsPage): guard send responses by chat
ibetitsmike Jul 25, 2026
2d7e4a5
fix(site/src/pages/AgentsPage): resync status only after fresh chat data
ibetitsmike Jul 25, 2026
790e71d
fix(site/src/pages/AgentsPage): keep websocket status through a resync
ibetitsmike Jul 25, 2026
00e0f1a
fix(site/src/pages/AgentsPage): scope the status resync to its own chat
ibetitsmike Jul 25, 2026
29e20d7
fix: require a configured audience for agent hook consumers
ibetitsmike Jul 25, 2026
8b25c8b
fix(scripts/agenthooks-server): decide pre_tool_use duplicates under …
ibetitsmike Jul 25, 2026
c4820d9
docs(docs/admin/setup): document the configured hook audience
ibetitsmike Jul 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cli/testdata/server-config.yaml.golden
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,17 @@ chat:
# opt-in settings.
# (default: false, type: bool)
debugLoggingEnabled: false
# HTTPS URL to receive chat agent lifecycle hook events. Hooks are disabled when
# unset. Requires the agent-lifecycle-hooks experiment.
# (default: <unset>, type: url)
hookURL:
# Maximum time to wait for a chat agent lifecycle hook response.
# (default: 1.5s, type: duration)
hookTimeout: 1.5s
# Whether to dispatch chat agent lifecycle hooks when a hook URL is configured.
# Requires the agent-lifecycle-hooks experiment.
# (default: true, type: bool)
hookEnabled: true
# Deprecated: AI Gateway routing is now the only routing path. Setting this value
# has no effect. This option will be removed in a future release.
# (default: true, type: bool)
Expand Down
57 changes: 50 additions & 7 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 50 additions & 7 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import (
"github.com/coder/coder/v2/coderd/workspacestats"
"github.com/coder/coder/v2/coderd/wsbuilder"
"github.com/coder/coder/v2/coderd/wsbuildorchestrator"
"github.com/coder/coder/v2/coderd/x/agenthooks/dispatch"
"github.com/coder/coder/v2/coderd/x/chatd"
"github.com/coder/coder/v2/coderd/x/chatd/chatprovider"
"github.com/coder/coder/v2/coderd/x/chatd/mcpclient"
Expand Down Expand Up @@ -878,6 +879,27 @@ func New(options *Options) *API {
// the chat daemon stays nil and chat HTTP handlers return a
// service-unavailable error with a clear remediation message.
if options.DeploymentValues.AI.BridgeConfig.Enabled.Value() {
var hookDispatcher *dispatch.Dispatcher
chatConfig := options.DeploymentValues.AI.Chat
hooksConfigured := chatConfig.HookURL.String() != "" && chatConfig.HookEnabled.Value()
hooksExperimentEnabled := experiments.Enabled(codersdk.ExperimentAgentLifecycleHooks)
if hooksConfigured && !hooksExperimentEnabled {
options.Logger.Warn(ctx, "chat lifecycle hooks are configured but inactive; enable the agent-lifecycle-hooks experiment to activate them",
slog.F("experiment", codersdk.ExperimentAgentLifecycleHooks),
)
}
if hooksConfigured && hooksExperimentEnabled {
hookDispatcher = dispatch.New(
options.Logger,
nil,
chatConfig.HookURL.String(),
chatConfig.HookSecret.Value(),
chatConfig.HookTimeout.Value(),
api.DeploymentID,
buildinfo.Version(),
options.PrometheusRegistry,
)
}
api.chatDaemon = chatd.New(options.Pubsub, chatd.Config{
Logger: options.Logger.Named("chatd"),
Database: options.Database,
Expand All @@ -897,6 +919,7 @@ func New(options *Options) *API {
StartWorkspace: api.chatStartWorkspace,
StopWorkspace: api.chatStopWorkspace,
WebpushDispatcher: options.WebPushDispatcher,
HookDispatcher: hookDispatcher,
UsageTracker: options.WorkspaceUsageTracker,
PrometheusRegistry: options.PrometheusRegistry,
OIDCTokenSource: oidcMCPSrc,
Expand Down
10 changes: 8 additions & 2 deletions coderd/database/db2sdk/db2sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -1638,11 +1638,17 @@ func chatMessageParts(m database.ChatMessage) ([]codersdk.ChatMessagePart, error
if err != nil {
return nil, err
}
// Strip internal-only fields before API responses.
// Strip internal-only fields before API responses. Hook context
// parts are model-only and must never reach clients.
filtered := parts[:0]
for i := range parts {
if parts[i].Type == codersdk.ChatMessagePartTypeHookContext {
continue
}
parts[i].StripInternal()
filtered = append(filtered, parts[i])
}
return parts, nil
return filtered, nil
}

func nullUUIDPtr(v uuid.NullUUID) *uuid.UUID {
Expand Down
15 changes: 15 additions & 0 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -7397,6 +7397,21 @@ func (q *querier) UpdateChatMCPServerIDs(ctx context.Context, arg database.Updat
return q.db.UpdateChatMCPServerIDs(ctx, arg)
}

func (q *querier) UpdateChatMessageContentByID(ctx context.Context, arg database.UpdateChatMessageContentByIDParams) (int64, error) {
message, err := q.db.GetChatMessageByID(ctx, arg.ID)
if err != nil {
return 0, err
}
chat, err := q.db.GetChatByID(ctx, message.ChatID)
if err != nil {
return 0, err
}
if err := q.authorizeContext(ctx, policy.ActionUpdate, chat); err != nil {
return 0, err
}
return q.db.UpdateChatMessageContentByID(ctx, arg)
}

func (q *querier) UpdateChatModelConfig(ctx context.Context, arg database.UpdateChatModelConfigParams) (database.ChatModelConfig, error) {
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceDeploymentConfig); err != nil {
return database.ChatModelConfig{}, err
Expand Down
11 changes: 11 additions & 0 deletions coderd/database/dbauthz/dbauthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,17 @@ func (s *MethodTestSuite) TestChats() {
dbm.EXPECT().InsertChatMessages(gomock.Any(), arg).Return(msgs, nil).AnyTimes()
check.Args(arg).Asserts(chat, policy.ActionUpdate).Returns(msgs)
}))

s.Run("UpdateChatMessageContentByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
chat := testutil.Fake(s.T(), faker, database.Chat{})
message := testutil.Fake(s.T(), faker, database.ChatMessage{ChatID: chat.ID})
arg := testutil.Fake(s.T(), faker, database.UpdateChatMessageContentByIDParams{ID: message.ID, ChatID: chat.ID})
dbm.EXPECT().GetChatMessageByID(gomock.Any(), message.ID).Return(message, nil).AnyTimes()
dbm.EXPECT().GetChatByID(gomock.Any(), chat.ID).Return(chat, nil).AnyTimes()
dbm.EXPECT().UpdateChatMessageContentByID(gomock.Any(), arg).Return(int64(1), nil).AnyTimes()
check.Args(arg).Asserts(chat, policy.ActionUpdate).Returns(int64(1))
}))

s.Run("InsertChatQueuedMessage", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
chat := testutil.Fake(s.T(), faker, database.Chat{})
arg := testutil.Fake(s.T(), faker, database.InsertChatQueuedMessageParams{ChatID: chat.ID})
Expand Down
1 change: 1 addition & 0 deletions coderd/database/dbgen/dbgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func Chat(t testing.TB, db database.Store, seed database.Chat) database.Chat {
}

chat, err := db.InsertChat(genCtx, database.InsertChatParams{
ID: uuid.NullUUID{UUID: seed.ID, Valid: seed.ID != uuid.Nil},
OrganizationID: takeFirst(seed.OrganizationID, uuid.New()),
OwnerID: takeFirst(seed.OwnerID, uuid.New()),
WorkspaceID: seed.WorkspaceID,
Expand Down
Loading
Loading