diff --git a/cli/sharing_test.go b/cli/sharing_test.go
index 71e153c64e..19e1853470 100644
--- a/cli/sharing_test.go
+++ b/cli/sharing_test.go
@@ -54,6 +54,7 @@ func TestSharingShare(t *testing.T) {
MinimalUser: codersdk.MinimalUser{
ID: toShareWithUser.ID,
Username: toShareWithUser.Username,
+ Name: toShareWithUser.Name,
AvatarURL: toShareWithUser.AvatarURL,
},
Role: codersdk.WorkspaceRole("use"),
@@ -103,6 +104,7 @@ func TestSharingShare(t *testing.T) {
MinimalUser: codersdk.MinimalUser{
ID: toShareWithUser1.ID,
Username: toShareWithUser1.Username,
+ Name: toShareWithUser1.Name,
AvatarURL: toShareWithUser1.AvatarURL,
},
Role: codersdk.WorkspaceRoleUse,
@@ -111,6 +113,7 @@ func TestSharingShare(t *testing.T) {
MinimalUser: codersdk.MinimalUser{
ID: toShareWithUser2.ID,
Username: toShareWithUser2.Username,
+ Name: toShareWithUser2.Name,
AvatarURL: toShareWithUser2.AvatarURL,
},
Role: codersdk.WorkspaceRoleUse,
@@ -155,6 +158,7 @@ func TestSharingShare(t *testing.T) {
MinimalUser: codersdk.MinimalUser{
ID: toShareWithUser.ID,
Username: toShareWithUser.Username,
+ Name: toShareWithUser.Name,
AvatarURL: toShareWithUser.AvatarURL,
},
Role: codersdk.WorkspaceRoleAdmin,
diff --git a/cli/testdata/coder_users_list_--help.golden b/cli/testdata/coder_users_list_--help.golden
index 22c1fe172f..e446d63a36 100644
--- a/cli/testdata/coder_users_list_--help.golden
+++ b/cli/testdata/coder_users_list_--help.golden
@@ -8,7 +8,7 @@ USAGE:
Aliases: ls
OPTIONS:
- -c, --column [id|username|email|created at|updated at|status] (default: username,email,created at,status)
+ -c, --column [id|username|name|email|created at|updated at|status] (default: username,email,created at,status)
Columns to display in table output.
--github-user-id int
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index 6c5cb1506f..585cc22710 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -11687,9 +11687,8 @@ const docTemplate = `{
"type": "string",
"format": "uuid"
},
- "initiator_id": {
- "type": "string",
- "format": "uuid"
+ "initiator": {
+ "$ref": "#/definitions/codersdk.MinimalUser"
},
"metadata": {
"type": "object",
@@ -15071,6 +15070,9 @@ const docTemplate = `{
"type": "string",
"format": "uuid"
},
+ "name": {
+ "type": "string"
+ },
"username": {
"type": "string"
}
@@ -20895,6 +20897,9 @@ const docTemplate = `{
"type": "string",
"format": "uuid"
},
+ "name": {
+ "type": "string"
+ },
"role": {
"enum": [
"admin",
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 1b492d7649..ac25626a03 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -10387,9 +10387,8 @@
"type": "string",
"format": "uuid"
},
- "initiator_id": {
- "type": "string",
- "format": "uuid"
+ "initiator": {
+ "$ref": "#/definitions/codersdk.MinimalUser"
},
"metadata": {
"type": "object",
@@ -13633,6 +13632,9 @@
"type": "string",
"format": "uuid"
},
+ "name": {
+ "type": "string"
+ },
"username": {
"type": "string"
}
@@ -19211,6 +19213,9 @@
"type": "string",
"format": "uuid"
},
+ "name": {
+ "type": "string"
+ },
"role": {
"enum": ["admin", "use"],
"allOf": [
diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go
index f28fa00407..77ddcbbf4a 100644
--- a/coderd/database/db2sdk/db2sdk.go
+++ b/coderd/database/db2sdk/db2sdk.go
@@ -189,6 +189,16 @@ func MinimalUser(user database.User) codersdk.MinimalUser {
return codersdk.MinimalUser{
ID: user.ID,
Username: user.Username,
+ Name: user.Name,
+ AvatarURL: user.AvatarURL,
+ }
+}
+
+func MinimalUserFromVisibleUser(user database.VisibleUser) codersdk.MinimalUser {
+ return codersdk.MinimalUser{
+ ID: user.ID,
+ Username: user.Username,
+ Name: user.Name,
AvatarURL: user.AvatarURL,
}
}
@@ -197,7 +207,6 @@ func ReducedUser(user database.User) codersdk.ReducedUser {
return codersdk.ReducedUser{
MinimalUser: MinimalUser(user),
Email: user.Email,
- Name: user.Name,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
LastSeenAt: user.LastSeenAt,
@@ -927,7 +936,7 @@ func PreviewParameterValidation(v *previewtypes.ParameterValidation) codersdk.Pr
}
}
-func AIBridgeInterception(interception database.AIBridgeInterception, tokenUsages []database.AIBridgeTokenUsage, userPrompts []database.AIBridgeUserPrompt, toolUsages []database.AIBridgeToolUsage) codersdk.AIBridgeInterception {
+func AIBridgeInterception(interception database.AIBridgeInterception, initiator database.VisibleUser, tokenUsages []database.AIBridgeTokenUsage, userPrompts []database.AIBridgeUserPrompt, toolUsages []database.AIBridgeToolUsage) codersdk.AIBridgeInterception {
sdkTokenUsages := List(tokenUsages, AIBridgeTokenUsage)
sort.Slice(sdkTokenUsages, func(i, j int) bool {
// created_at ASC
@@ -945,7 +954,7 @@ func AIBridgeInterception(interception database.AIBridgeInterception, tokenUsage
})
return codersdk.AIBridgeInterception{
ID: interception.ID,
- InitiatorID: interception.InitiatorID,
+ Initiator: MinimalUserFromVisibleUser(initiator),
Provider: interception.Provider,
Model: interception.Model,
Metadata: jsonOrEmptyMap(interception.Metadata),
diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go
index ccd6151e88..f1b262047a 100644
--- a/coderd/database/dbauthz/dbauthz.go
+++ b/coderd/database/dbauthz/dbauthz.go
@@ -4461,7 +4461,7 @@ func (q *querier) InsertWorkspaceResourceMetadata(ctx context.Context, arg datab
return q.db.InsertWorkspaceResourceMetadata(ctx, arg)
}
-func (q *querier) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.AIBridgeInterception, error) {
+func (q *querier) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.ListAIBridgeInterceptionsRow, error) {
prep, err := prepareSQLFilter(ctx, q.auth, policy.ActionRead, rbac.ResourceAibridgeInterception.Type)
if err != nil {
return nil, xerrors.Errorf("(dev error) prepare sql filter: %w", err)
@@ -5870,7 +5870,7 @@ func (q *querier) CountAuthorizedConnectionLogs(ctx context.Context, arg databas
return q.CountConnectionLogs(ctx, arg)
}
-func (q *querier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, _ rbac.PreparedAuthorized) ([]database.AIBridgeInterception, error) {
+func (q *querier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, _ rbac.PreparedAuthorized) ([]database.ListAIBridgeInterceptionsRow, error) {
// TODO: Delete this function, all ListAIBridgeInterceptions should be authorized. For now just call ListAIBridgeInterceptions on the authz querier.
// This cannot be deleted for now because it's included in the
// database.Store interface, so dbauthz needs to implement it.
diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index 1137aa250d..feb78215c5 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -4537,14 +4537,14 @@ func (s *MethodTestSuite) TestAIBridge() {
s.Run("ListAIBridgeInterceptions", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
params := database.ListAIBridgeInterceptionsParams{}
- db.EXPECT().ListAuthorizedAIBridgeInterceptions(gomock.Any(), params, gomock.Any()).Return([]database.AIBridgeInterception{}, nil).AnyTimes()
+ db.EXPECT().ListAuthorizedAIBridgeInterceptions(gomock.Any(), params, gomock.Any()).Return([]database.ListAIBridgeInterceptionsRow{}, nil).AnyTimes()
// No asserts here because SQLFilter.
check.Args(params).Asserts()
}))
s.Run("ListAuthorizedAIBridgeInterceptions", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
params := database.ListAIBridgeInterceptionsParams{}
- db.EXPECT().ListAuthorizedAIBridgeInterceptions(gomock.Any(), params, gomock.Any()).Return([]database.AIBridgeInterception{}, nil).AnyTimes()
+ db.EXPECT().ListAuthorizedAIBridgeInterceptions(gomock.Any(), params, gomock.Any()).Return([]database.ListAIBridgeInterceptionsRow{}, nil).AnyTimes()
// No asserts here because SQLFilter.
check.Args(params, emptyPreparedAuthorized{}).Asserts()
}))
diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go
index cdcc675c91..9b678a8e27 100644
--- a/coderd/database/dbmetrics/querymetrics.go
+++ b/coderd/database/dbmetrics/querymetrics.go
@@ -2714,7 +2714,7 @@ func (m queryMetricsStore) InsertWorkspaceResourceMetadata(ctx context.Context,
return metadata, err
}
-func (m queryMetricsStore) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.AIBridgeInterception, error) {
+func (m queryMetricsStore) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.ListAIBridgeInterceptionsRow, error) {
start := time.Now()
r0, r1 := m.s.ListAIBridgeInterceptions(ctx, arg)
m.queryLatencies.WithLabelValues("ListAIBridgeInterceptions").Observe(time.Since(start).Seconds())
@@ -3722,7 +3722,7 @@ func (m queryMetricsStore) CountAuthorizedConnectionLogs(ctx context.Context, ar
return r0, r1
}
-func (m queryMetricsStore) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]database.AIBridgeInterception, error) {
+func (m queryMetricsStore) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]database.ListAIBridgeInterceptionsRow, error) {
start := time.Now()
r0, r1 := m.s.ListAuthorizedAIBridgeInterceptions(ctx, arg, prepared)
m.queryLatencies.WithLabelValues("ListAuthorizedAIBridgeInterceptions").Observe(time.Since(start).Seconds())
diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go
index 89099b6e71..06b7f7ae3e 100644
--- a/coderd/database/dbmock/dbmock.go
+++ b/coderd/database/dbmock/dbmock.go
@@ -5804,10 +5804,10 @@ func (mr *MockStoreMockRecorder) InsertWorkspaceResourceMetadata(ctx, arg any) *
}
// ListAIBridgeInterceptions mocks base method.
-func (m *MockStore) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.AIBridgeInterception, error) {
+func (m *MockStore) ListAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams) ([]database.ListAIBridgeInterceptionsRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAIBridgeInterceptions", ctx, arg)
- ret0, _ := ret[0].([]database.AIBridgeInterception)
+ ret0, _ := ret[0].([]database.ListAIBridgeInterceptionsRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -5864,10 +5864,10 @@ func (mr *MockStoreMockRecorder) ListAIBridgeUserPromptsByInterceptionIDs(ctx, i
}
// ListAuthorizedAIBridgeInterceptions mocks base method.
-func (m *MockStore) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]database.AIBridgeInterception, error) {
+func (m *MockStore) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg database.ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]database.ListAIBridgeInterceptionsRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListAuthorizedAIBridgeInterceptions", ctx, arg, prepared)
- ret0, _ := ret[0].([]database.AIBridgeInterception)
+ ret0, _ := ret[0].([]database.ListAIBridgeInterceptionsRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql
index 323b595c10..a01ddb8d1f 100644
--- a/coderd/database/dump.sql
+++ b/coderd/database/dump.sql
@@ -3511,6 +3511,9 @@ COMMENT ON TRIGGER workspace_agent_name_unique_trigger ON workspace_agents IS 'U
the uniqueness requirement. A trigger allows us to enforce uniqueness going
forward without requiring a migration to clean up historical data.';
+ALTER TABLE ONLY aibridge_interceptions
+ ADD CONSTRAINT aibridge_interceptions_initiator_id_fkey FOREIGN KEY (initiator_id) REFERENCES users(id);
+
ALTER TABLE ONLY api_keys
ADD CONSTRAINT api_keys_user_id_uuid_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
diff --git a/coderd/database/foreign_key_constraint.go b/coderd/database/foreign_key_constraint.go
index 4c629797d1..6737275dd3 100644
--- a/coderd/database/foreign_key_constraint.go
+++ b/coderd/database/foreign_key_constraint.go
@@ -6,6 +6,7 @@ type ForeignKeyConstraint string
// ForeignKeyConstraint enums.
const (
+ ForeignKeyAibridgeInterceptionsInitiatorID ForeignKeyConstraint = "aibridge_interceptions_initiator_id_fkey" // ALTER TABLE ONLY aibridge_interceptions ADD CONSTRAINT aibridge_interceptions_initiator_id_fkey FOREIGN KEY (initiator_id) REFERENCES users(id);
ForeignKeyAPIKeysUserIDUUID ForeignKeyConstraint = "api_keys_user_id_uuid_fkey" // ALTER TABLE ONLY api_keys ADD CONSTRAINT api_keys_user_id_uuid_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ForeignKeyConnectionLogsOrganizationID ForeignKeyConstraint = "connection_logs_organization_id_fkey" // ALTER TABLE ONLY connection_logs ADD CONSTRAINT connection_logs_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ForeignKeyConnectionLogsWorkspaceID ForeignKeyConstraint = "connection_logs_workspace_id_fkey" // ALTER TABLE ONLY connection_logs ADD CONSTRAINT connection_logs_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
diff --git a/coderd/database/migrations/000385_aibridge_fks.down.sql b/coderd/database/migrations/000385_aibridge_fks.down.sql
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/coderd/database/migrations/000385_aibridge_fks.up.sql b/coderd/database/migrations/000385_aibridge_fks.up.sql
new file mode 100644
index 0000000000..cc9cfbfdd9
--- /dev/null
+++ b/coderd/database/migrations/000385_aibridge_fks.up.sql
@@ -0,0 +1,49 @@
+-- We didn't add an FK as a premature optimization when the aibridge tables were
+-- added, but for the initiator_id it's pretty annoying not having a strong
+-- reference.
+--
+-- Since the aibridge feature is still in early access, we're going to add the
+-- FK and drop any rows that violate it (which should be none). This isn't a
+-- very efficient migration, but since the feature is behind an experimental
+-- flag, it shouldn't have any impact on deployments that aren't using the
+-- feature.
+
+-- Step 1: Add FK without validating it
+ALTER TABLE aibridge_interceptions
+ ADD CONSTRAINT aibridge_interceptions_initiator_id_fkey
+ FOREIGN KEY (initiator_id)
+ REFERENCES users(id)
+ -- We can't:
+ -- - Cascade delete because this is an auditing feature, and it also
+ -- wouldn't delete related aibridge rows since we don't FK them.
+ -- - Set null because you can't correlate to the original user ID if the
+ -- user somehow gets deleted.
+ --
+ -- So we just use the default and don't do anything. This will result in a
+ -- deferred constraint violation error when the user is deleted.
+ --
+ -- In Coder, we don't delete user rows ever, so this should never happen
+ -- unless an admin manually deletes a user with SQL.
+ ON DELETE NO ACTION
+ -- Delay validation of existing data until after we've dropped rows that
+ -- violate the FK.
+ NOT VALID;
+
+-- Step 2: Drop existing interceptions that violate the FK.
+DELETE FROM aibridge_interceptions
+WHERE initiator_id NOT IN (SELECT id FROM users);
+
+-- Step 3: Drop existing rows from other tables that no longer have a valid
+-- interception in the database.
+DELETE FROM aibridge_token_usages
+WHERE interception_id NOT IN (SELECT id FROM aibridge_interceptions);
+
+DELETE FROM aibridge_user_prompts
+WHERE interception_id NOT IN (SELECT id FROM aibridge_interceptions);
+
+DELETE FROM aibridge_tool_usages
+WHERE interception_id NOT IN (SELECT id FROM aibridge_interceptions);
+
+-- Step 4: Validate the FK
+ALTER TABLE aibridge_interceptions
+ VALIDATE CONSTRAINT aibridge_interceptions_initiator_id_fkey;
diff --git a/coderd/database/migrations/testdata/fixtures/000370_aibridge.up.sql b/coderd/database/migrations/testdata/fixtures/000370_aibridge.up.sql
index 0a66555eea..ef49405ae6 100644
--- a/coderd/database/migrations/testdata/fixtures/000370_aibridge.up.sql
+++ b/coderd/database/migrations/testdata/fixtures/000370_aibridge.up.sql
@@ -8,7 +8,7 @@ INSERT INTO
)
VALUES (
'be003e1e-b38f-43bf-847d-928074dd0aa8',
- '30095c71-380b-457a-8995-97b8ee6e5307',
+ '30095c71-380b-457a-8995-97b8ee6e5307', -- admin@coder.com, from 000022_initial_v0.6.6.up.sql
'openai',
'gpt-5',
'2025-09-15 12:45:13.921148+00'
@@ -77,3 +77,82 @@ VALUES (
'{}',
'2025-09-15 12:45:21.674335+00'
);
+
+-- For a later migration, we'll add an invalid interception without a valid
+-- initiator_id.
+INSERT INTO
+ aibridge_interceptions (
+ id,
+ initiator_id,
+ provider,
+ model,
+ started_at
+ )
+VALUES (
+ 'c6d29c6e-26a3-4137-bb2e-9dfeef3c1c26',
+ 'cab8d56a-8922-4999-81a9-046b43ac1312', -- user does not exist
+ 'openai',
+ 'gpt-5',
+ '2025-09-15 12:45:13.921148+00'
+ );
+INSERT INTO
+ aibridge_token_usages (
+ id,
+ interception_id,
+ provider_response_id,
+ input_tokens,
+ output_tokens,
+ metadata,
+ created_at
+ )
+VALUES (
+ '5650db6c-0b7c-49e3-bb26-9b2ba0107e11',
+ 'c6d29c6e-26a3-4137-bb2e-9dfeef3c1c26',
+ 'chatcmpl-CG2s28QlpKIoooUtXuLTmGbdtyS1k',
+ 10950,
+ 118,
+ '{}',
+ '2025-09-15 12:45:21.674413+00'
+ );
+INSERT INTO
+ aibridge_user_prompts (
+ id,
+ interception_id,
+ provider_response_id,
+ prompt,
+ metadata,
+ created_at
+ )
+VALUES (
+ '1e76cb5b-7c34-4160-b604-a4256f856169',
+ 'c6d29c6e-26a3-4137-bb2e-9dfeef3c1c26',
+ 'chatcmpl-CG2s28QlpKIoooUtXuLTmGbdtyS1k',
+ 'how many workspaces do i have',
+ '{}',
+ '2025-09-15 12:45:21.674335+00'
+ );
+INSERT INTO
+ aibridge_tool_usages (
+ id,
+ interception_id,
+ provider_response_id,
+ tool,
+ server_url,
+ input,
+ injected,
+ invocation_error,
+ metadata,
+ created_at
+ )
+VALUES (
+ '351b440f-d605-4f37-8ceb-011f0377b695',
+ 'c6d29c6e-26a3-4137-bb2e-9dfeef3c1c26',
+ 'chatcmpl-CG2s28QlpKIoooUtXuLTmGbdtyS1k',
+ 'coder_list_workspaces',
+ 'http://localhost:3000/api/experimental/mcp/http',
+ '{}',
+ true,
+ NULL,
+ '{}',
+ '2025-09-15 12:45:21.674413+00'
+ );
diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go
index 654dfb8b37..1400893a26 100644
--- a/coderd/database/modelqueries.go
+++ b/coderd/database/modelqueries.go
@@ -763,11 +763,11 @@ func (q *sqlQuerier) CountAuthorizedConnectionLogs(ctx context.Context, arg Coun
}
type aibridgeQuerier interface {
- ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]AIBridgeInterception, error)
+ ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]ListAIBridgeInterceptionsRow, error)
CountAuthorizedAIBridgeInterceptions(ctx context.Context, arg CountAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) (int64, error)
}
-func (q *sqlQuerier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]AIBridgeInterception, error) {
+func (q *sqlQuerier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams, prepared rbac.PreparedAuthorized) ([]ListAIBridgeInterceptionsRow, error) {
authorizedFilter, err := prepared.CompileToSQL(ctx, regosql.ConvertConfig{
VariableConverter: regosql.AIBridgeInterceptionConverter(),
})
@@ -794,16 +794,20 @@ func (q *sqlQuerier) ListAuthorizedAIBridgeInterceptions(ctx context.Context, ar
return nil, err
}
defer rows.Close()
- var items []AIBridgeInterception
+ var items []ListAIBridgeInterceptionsRow
for rows.Next() {
- var i AIBridgeInterception
+ var i ListAIBridgeInterceptionsRow
if err := rows.Scan(
- &i.ID,
- &i.InitiatorID,
- &i.Provider,
- &i.Model,
- &i.StartedAt,
- &i.Metadata,
+ &i.AIBridgeInterception.ID,
+ &i.AIBridgeInterception.InitiatorID,
+ &i.AIBridgeInterception.Provider,
+ &i.AIBridgeInterception.Model,
+ &i.AIBridgeInterception.StartedAt,
+ &i.AIBridgeInterception.Metadata,
+ &i.VisibleUser.ID,
+ &i.VisibleUser.Username,
+ &i.VisibleUser.Name,
+ &i.VisibleUser.AvatarURL,
); err != nil {
return nil, err
}
diff --git a/coderd/database/querier.go b/coderd/database/querier.go
index 3e2d655f44..3a83275297 100644
--- a/coderd/database/querier.go
+++ b/coderd/database/querier.go
@@ -592,7 +592,7 @@ type sqlcQuerier interface {
InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspaceProxyParams) (WorkspaceProxy, error)
InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error)
InsertWorkspaceResourceMetadata(ctx context.Context, arg InsertWorkspaceResourceMetadataParams) ([]WorkspaceResourceMetadatum, error)
- ListAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams) ([]AIBridgeInterception, error)
+ ListAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams) ([]ListAIBridgeInterceptionsRow, error)
ListAIBridgeTokenUsagesByInterceptionIDs(ctx context.Context, interceptionIds []uuid.UUID) ([]AIBridgeTokenUsage, error)
ListAIBridgeToolUsagesByInterceptionIDs(ctx context.Context, interceptionIds []uuid.UUID) ([]AIBridgeToolUsage, error)
ListAIBridgeUserPromptsByInterceptionIDs(ctx context.Context, interceptionIds []uuid.UUID) ([]AIBridgeUserPrompt, error)
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index c0fd6eb64d..5b4cf7b21e 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -528,9 +528,12 @@ func (q *sqlQuerier) InsertAIBridgeUserPrompt(ctx context.Context, arg InsertAIB
const listAIBridgeInterceptions = `-- name: ListAIBridgeInterceptions :many
SELECT
- id, initiator_id, provider, model, started_at, metadata
+ aibridge_interceptions.id, aibridge_interceptions.initiator_id, aibridge_interceptions.provider, aibridge_interceptions.model, aibridge_interceptions.started_at, aibridge_interceptions.metadata,
+ visible_users.id, visible_users.username, visible_users.name, visible_users.avatar_url
FROM
aibridge_interceptions
+JOIN
+ visible_users ON visible_users.id = aibridge_interceptions.initiator_id
WHERE
-- Filter by time frame
CASE
@@ -592,7 +595,12 @@ type ListAIBridgeInterceptionsParams struct {
Limit int32 `db:"limit_" json:"limit_"`
}
-func (q *sqlQuerier) ListAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams) ([]AIBridgeInterception, error) {
+type ListAIBridgeInterceptionsRow struct {
+ AIBridgeInterception AIBridgeInterception `db:"aibridge_interception" json:"aibridge_interception"`
+ VisibleUser VisibleUser `db:"visible_user" json:"visible_user"`
+}
+
+func (q *sqlQuerier) ListAIBridgeInterceptions(ctx context.Context, arg ListAIBridgeInterceptionsParams) ([]ListAIBridgeInterceptionsRow, error) {
rows, err := q.db.QueryContext(ctx, listAIBridgeInterceptions,
arg.StartedAfter,
arg.StartedBefore,
@@ -607,16 +615,20 @@ func (q *sqlQuerier) ListAIBridgeInterceptions(ctx context.Context, arg ListAIBr
return nil, err
}
defer rows.Close()
- var items []AIBridgeInterception
+ var items []ListAIBridgeInterceptionsRow
for rows.Next() {
- var i AIBridgeInterception
+ var i ListAIBridgeInterceptionsRow
if err := rows.Scan(
- &i.ID,
- &i.InitiatorID,
- &i.Provider,
- &i.Model,
- &i.StartedAt,
- &i.Metadata,
+ &i.AIBridgeInterception.ID,
+ &i.AIBridgeInterception.InitiatorID,
+ &i.AIBridgeInterception.Provider,
+ &i.AIBridgeInterception.Model,
+ &i.AIBridgeInterception.StartedAt,
+ &i.AIBridgeInterception.Metadata,
+ &i.VisibleUser.ID,
+ &i.VisibleUser.Username,
+ &i.VisibleUser.Name,
+ &i.VisibleUser.AvatarURL,
); err != nil {
return nil, err
}
diff --git a/coderd/database/queries/aibridge.sql b/coderd/database/queries/aibridge.sql
index 32e0246447..3a3b63b848 100644
--- a/coderd/database/queries/aibridge.sql
+++ b/coderd/database/queries/aibridge.sql
@@ -111,9 +111,12 @@ WHERE
-- name: ListAIBridgeInterceptions :many
SELECT
- *
+ sqlc.embed(aibridge_interceptions),
+ sqlc.embed(visible_users)
FROM
aibridge_interceptions
+JOIN
+ visible_users ON visible_users.id = aibridge_interceptions.initiator_id
WHERE
-- Filter by time frame
CASE
diff --git a/coderd/templateversions.go b/coderd/templateversions.go
index 17a4d9b451..2e959702fb 100644
--- a/coderd/templateversions.go
+++ b/coderd/templateversions.go
@@ -1958,6 +1958,7 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi
CreatedBy: codersdk.MinimalUser{
ID: version.CreatedBy,
Username: version.CreatedByUsername,
+ Name: version.CreatedByName,
AvatarURL: version.CreatedByAvatarURL,
},
Archived: version.Archived,
diff --git a/codersdk/aibridge.go b/codersdk/aibridge.go
index 05f1e1a6fc..0a6e85c947 100644
--- a/codersdk/aibridge.go
+++ b/codersdk/aibridge.go
@@ -13,7 +13,7 @@ import (
type AIBridgeInterception struct {
ID uuid.UUID `json:"id" format:"uuid"`
- InitiatorID uuid.UUID `json:"initiator_id" format:"uuid"`
+ Initiator MinimalUser `json:"initiator"`
Provider string `json:"provider"`
Model string `json:"model"`
Metadata map[string]any `json:"metadata"`
diff --git a/codersdk/users.go b/codersdk/users.go
index 266ef8c598..44464f9476 100644
--- a/codersdk/users.go
+++ b/codersdk/users.go
@@ -41,6 +41,7 @@ type UsersRequest struct {
type MinimalUser struct {
ID uuid.UUID `json:"id" validate:"required" table:"id" format:"uuid"`
Username string `json:"username" validate:"required" table:"username,default_sort"`
+ Name string `json:"name,omitempty" table:"name"`
AvatarURL string `json:"avatar_url,omitempty" format:"uri"`
}
@@ -50,7 +51,6 @@ type MinimalUser struct {
// required by the frontend.
type ReducedUser struct {
MinimalUser `table:"m,recursive_inline"`
- Name string `json:"name,omitempty"`
Email string `json:"email" validate:"required" table:"email" format:"email"`
CreatedAt time.Time `json:"created_at" validate:"required" table:"created at" format:"date-time"`
UpdatedAt time.Time `json:"updated_at" table:"updated at" format:"date-time"`
diff --git a/docs/reference/api/aibridge.md b/docs/reference/api/aibridge.md
index 35af663993..54f408ec23 100644
--- a/docs/reference/api/aibridge.md
+++ b/docs/reference/api/aibridge.md
@@ -31,7 +31,12 @@ curl -X GET http://coder-server:8080/api/v2/api/experimental/aibridge/intercepti
"results": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
+ "initiator": {
+ "avatar_url": "http://example.com",
+ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
+ "username": "string"
+ },
"metadata": {
"property1": null,
"property2": null
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index 654dc0f45b..a36199a6f6 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -436,7 +436,12 @@
```json
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
+ "initiator": {
+ "avatar_url": "http://example.com",
+ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
+ "username": "string"
+ },
"metadata": {
"property1": null,
"property2": null
@@ -496,7 +501,7 @@
| Name | Type | Required | Restrictions | Description |
|--------------------|---------------------------------------------------------------------|----------|--------------|-------------|
| `id` | string | false | | |
-| `initiator_id` | string | false | | |
+| `initiator` | [codersdk.MinimalUser](#codersdkminimaluser) | false | | |
| `metadata` | object | false | | |
| » `[any property]` | any | false | | |
| `model` | string | false | | |
@@ -513,7 +518,12 @@
"results": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
+ "initiator": {
+ "avatar_url": "http://example.com",
+ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
+ "username": "string"
+ },
"metadata": {
"property1": null,
"property2": null
@@ -4947,6 +4957,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
{
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
}
```
@@ -4957,6 +4968,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|--------------|--------|----------|--------------|-------------|
| `avatar_url` | string | false | | |
| `id` | string | true | | |
+| `name` | string | false | | |
| `username` | string | true | | |
## codersdk.NotificationMethodsResponse
@@ -8558,6 +8570,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -10129,6 +10142,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
{
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"role": "admin",
"username": "string"
}
@@ -11769,6 +11783,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
{
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"role": "admin",
"username": "string"
}
@@ -11780,6 +11795,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|--------------|--------------------------------------------------|----------|--------------|-------------|
| `avatar_url` | string | false | | |
| `id` | string | true | | |
+| `name` | string | false | | |
| `role` | [codersdk.WorkspaceRole](#codersdkworkspacerole) | false | | |
| `username` | string | true | | |
diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md
index 9d69949ac7..2c516f4788 100644
--- a/docs/reference/api/templates.md
+++ b/docs/reference/api/templates.md
@@ -460,6 +460,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -561,6 +562,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -686,6 +688,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -1294,6 +1297,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -1374,6 +1378,7 @@ Status Code **200**
| `» created_by` | [codersdk.MinimalUser](schemas.md#codersdkminimaluser) | false | | |
| `»» avatar_url` | string(uri) | false | | |
| `»» id` | string(uuid) | true | | |
+| `»» name` | string | false | | |
| `»» username` | string | true | | |
| `» has_external_agent` | boolean | false | | |
| `» id` | string(uuid) | false | | |
@@ -1579,6 +1584,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -1659,6 +1665,7 @@ Status Code **200**
| `» created_by` | [codersdk.MinimalUser](schemas.md#codersdkminimaluser) | false | | |
| `»» avatar_url` | string(uri) | false | | |
| `»» id` | string(uuid) | true | | |
+| `»» name` | string | false | | |
| `»» username` | string | true | | |
| `» has_external_agent` | boolean | false | | |
| `» id` | string(uuid) | false | | |
@@ -1754,6 +1761,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
@@ -1864,6 +1872,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}
"created_by": {
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"username": "string"
},
"has_external_agent": true,
diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md
index e2a95613ed..86c04f79c4 100644
--- a/docs/reference/api/workspaces.md
+++ b/docs/reference/api/workspaces.md
@@ -1588,6 +1588,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/acl \
{
"avatar_url": "http://example.com",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "name": "string",
"role": "admin",
"username": "string"
}
diff --git a/docs/reference/cli/users_list.md b/docs/reference/cli/users_list.md
index 93122e7741..7217a8267b 100644
--- a/docs/reference/cli/users_list.md
+++ b/docs/reference/cli/users_list.md
@@ -25,10 +25,10 @@ Filter users by their GitHub user ID.
### -c, --column
-| | |
-|---------|--------------------------------------------------------------------|
-| Type | [id\|username\|email\|created at\|updated at\|status] |
-| Default | username,email,created at,status |
+| | |
+|---------|--------------------------------------------------------------------------|
+| Type | [id\|username\|name\|email\|created at\|updated at\|status] |
+| Default | username,email,created at,status |
Columns to display in table output.
diff --git a/enterprise/coderd/aibridge.go b/enterprise/coderd/aibridge.go
index 878e8ac741..2c28745c95 100644
--- a/enterprise/coderd/aibridge.go
+++ b/enterprise/coderd/aibridge.go
@@ -75,7 +75,7 @@ func (api *API) aiBridgeListInterceptions(rw http.ResponseWriter, r *http.Reques
var (
count int64
- rows []database.AIBridgeInterception
+ rows []database.ListAIBridgeInterceptionsRow
)
err := api.Database.InTx(func(db database.Store) error {
// Ensure the after_id interception exists and is visible to the user.
@@ -132,10 +132,10 @@ func (api *API) aiBridgeListInterceptions(rw http.ResponseWriter, r *http.Reques
})
}
-func populatedAndConvertAIBridgeInterceptions(ctx context.Context, db database.Store, dbInterceptions []database.AIBridgeInterception) ([]codersdk.AIBridgeInterception, error) {
+func populatedAndConvertAIBridgeInterceptions(ctx context.Context, db database.Store, dbInterceptions []database.ListAIBridgeInterceptionsRow) ([]codersdk.AIBridgeInterception, error) {
ids := make([]uuid.UUID, len(dbInterceptions))
for i, row := range dbInterceptions {
- ids[i] = row.ID
+ ids[i] = row.AIBridgeInterception.ID
}
//nolint:gocritic // This is a system function until we implement a join for aibridge interceptions. AIBridge interception subresources use the same authorization call as their parent.
@@ -170,7 +170,13 @@ func populatedAndConvertAIBridgeInterceptions(ctx context.Context, db database.S
items := make([]codersdk.AIBridgeInterception, len(dbInterceptions))
for i, row := range dbInterceptions {
- items[i] = db2sdk.AIBridgeInterception(row, tokenUsagesMap[row.ID], userPromptsMap[row.ID], toolUsagesMap[row.ID])
+ items[i] = db2sdk.AIBridgeInterception(
+ row.AIBridgeInterception,
+ row.VisibleUser,
+ tokenUsagesMap[row.AIBridgeInterception.ID],
+ userPromptsMap[row.AIBridgeInterception.ID],
+ toolUsagesMap[row.AIBridgeInterception.ID],
+ )
}
return items, nil
diff --git a/enterprise/coderd/aibridge_test.go b/enterprise/coderd/aibridge_test.go
index 4d8cac139d..232cfd7072 100644
--- a/enterprise/coderd/aibridge_test.go
+++ b/enterprise/coderd/aibridge_test.go
@@ -72,7 +72,7 @@ func TestAIBridgeListInterceptions(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{string(codersdk.ExperimentAIBridge)}
- client, db, _ := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
+ client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
@@ -85,10 +85,28 @@ func TestAIBridgeListInterceptions(t *testing.T) {
experimentalClient := codersdk.NewExperimentalClient(client)
ctx := testutil.Context(t, testutil.WaitLong)
+ user1, err := client.User(ctx, codersdk.Me)
+ require.NoError(t, err)
+ user1Visible := database.VisibleUser{
+ ID: user1.ID,
+ Username: user1.Username,
+ Name: user1.Name,
+ AvatarURL: user1.AvatarURL,
+ }
+
+ _, user2 := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
+ user2Visible := database.VisibleUser{
+ ID: user2.ID,
+ Username: user2.Username,
+ Name: user2.Name,
+ AvatarURL: user2.AvatarURL,
+ }
+
// Insert a bunch of test data.
now := dbtime.Now()
i1 := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
- StartedAt: now.Add(-time.Hour),
+ InitiatorID: user1.ID,
+ StartedAt: now.Add(-time.Hour),
})
i1tok1 := dbgen.AIBridgeTokenUsage(t, db, database.InsertAIBridgeTokenUsageParams{
InterceptionID: i1.ID,
@@ -115,14 +133,15 @@ func TestAIBridgeListInterceptions(t *testing.T) {
CreatedAt: now.Add(-time.Minute),
})
i2 := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
- StartedAt: now,
+ InitiatorID: user2.ID,
+ StartedAt: now,
})
// Convert to SDK types for response comparison.
// You may notice that the ordering of the inner arrays are ASC, this is
// intentional.
- i1SDK := db2sdk.AIBridgeInterception(i1, []database.AIBridgeTokenUsage{i1tok2, i1tok1}, []database.AIBridgeUserPrompt{i1up2, i1up1}, []database.AIBridgeToolUsage{i1tool2, i1tool1})
- i2SDK := db2sdk.AIBridgeInterception(i2, nil, nil, nil)
+ i1SDK := db2sdk.AIBridgeInterception(i1, user1Visible, []database.AIBridgeTokenUsage{i1tok2, i1tok1}, []database.AIBridgeUserPrompt{i1up2, i1up1}, []database.AIBridgeToolUsage{i1tool2, i1tool1})
+ i2SDK := db2sdk.AIBridgeInterception(i2, user2Visible, nil, nil, nil)
res, err := experimentalClient.AIBridgeListInterceptions(ctx, codersdk.AIBridgeListInterceptionsFilter{})
require.NoError(t, err)
@@ -158,7 +177,7 @@ func TestAIBridgeListInterceptions(t *testing.T) {
dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{string(codersdk.ExperimentAIBridge)}
- client, db, _ := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
+ client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
@@ -178,8 +197,9 @@ func TestAIBridgeListInterceptions(t *testing.T) {
now := dbtime.Now()
for i := range 10 {
interception := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
- ID: uuid.UUID{byte(i)},
- StartedAt: now,
+ ID: uuid.UUID{byte(i)},
+ InitiatorID: firstUser.UserID,
+ StartedAt: now,
})
allInterceptionIDs = append(allInterceptionIDs, interception.ID)
}
@@ -190,8 +210,9 @@ func TestAIBridgeListInterceptions(t *testing.T) {
require.NoError(t, err)
randomOffsetDur := time.Duration(randomOffset) * time.Second
interception := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
- ID: uuid.UUID{byte(i + 10)},
- StartedAt: now.Add(randomOffsetDur),
+ ID: uuid.UUID{byte(i + 10)},
+ InitiatorID: firstUser.UserID,
+ StartedAt: now.Add(randomOffsetDur),
})
allInterceptionIDs = append(allInterceptionIDs, interception.ID)
}
@@ -329,27 +350,44 @@ func TestAIBridgeListInterceptions(t *testing.T) {
},
})
experimentalClient := codersdk.NewExperimentalClient(client)
- _, secondUser := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
+ ctx := testutil.Context(t, testutil.WaitLong)
+
+ user1, err := client.User(ctx, codersdk.Me)
+ require.NoError(t, err)
+ user1Visible := database.VisibleUser{
+ ID: user1.ID,
+ Username: user1.Username,
+ Name: user1.Name,
+ AvatarURL: user1.AvatarURL,
+ }
+
+ _, user2 := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
+ user2Visible := database.VisibleUser{
+ ID: user2.ID,
+ Username: user2.Username,
+ Name: user2.Name,
+ AvatarURL: user2.AvatarURL,
+ }
// Insert a bunch of test data with varying filterable fields.
now := dbtime.Now()
i1 := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
ID: uuid.MustParse("00000000-0000-0000-0000-000000000001"),
- InitiatorID: firstUser.UserID,
+ InitiatorID: user1.ID,
Provider: "one",
Model: "one",
StartedAt: now,
})
i2 := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
ID: uuid.MustParse("00000000-0000-0000-0000-000000000002"),
- InitiatorID: firstUser.UserID,
+ InitiatorID: user1.ID,
Provider: "two",
Model: "two",
StartedAt: now.Add(-time.Hour),
})
i3 := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
ID: uuid.MustParse("00000000-0000-0000-0000-000000000003"),
- InitiatorID: secondUser.ID,
+ InitiatorID: user2.ID,
Provider: "three",
Model: "three",
StartedAt: now.Add(-2 * time.Hour),
@@ -357,9 +395,9 @@ func TestAIBridgeListInterceptions(t *testing.T) {
// Convert to SDK types for response comparison. We don't care about the
// inner arrays for this test.
- i1SDK := db2sdk.AIBridgeInterception(i1, nil, nil, nil)
- i2SDK := db2sdk.AIBridgeInterception(i2, nil, nil, nil)
- i3SDK := db2sdk.AIBridgeInterception(i3, nil, nil, nil)
+ i1SDK := db2sdk.AIBridgeInterception(i1, user1Visible, nil, nil, nil)
+ i2SDK := db2sdk.AIBridgeInterception(i2, user1Visible, nil, nil, nil)
+ i3SDK := db2sdk.AIBridgeInterception(i3, user2Visible, nil, nil, nil)
cases := []struct {
name string
@@ -383,12 +421,12 @@ func TestAIBridgeListInterceptions(t *testing.T) {
},
{
name: "Initiator/UserID",
- filter: codersdk.AIBridgeListInterceptionsFilter{Initiator: secondUser.ID.String()},
+ filter: codersdk.AIBridgeListInterceptionsFilter{Initiator: user2.ID.String()},
want: []codersdk.AIBridgeInterception{i3SDK},
},
{
name: "Initiator/Username",
- filter: codersdk.AIBridgeListInterceptionsFilter{Initiator: secondUser.Username},
+ filter: codersdk.AIBridgeListInterceptionsFilter{Initiator: user2.Username},
want: []codersdk.AIBridgeInterception{i3SDK},
},
{
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 932f72a383..65b1d2d3e5 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -26,7 +26,7 @@ export interface AIBridgeConfig {
// From codersdk/aibridge.go
export interface AIBridgeInterception {
readonly id: string;
- readonly initiator_id: string;
+ readonly initiator: MinimalUser;
readonly provider: string;
readonly model: string;
// empty interface{} type, falling back to unknown
@@ -2638,6 +2638,7 @@ export interface MinimalOrganization {
export interface MinimalUser {
readonly id: string;
readonly username: string;
+ readonly name?: string;
readonly avatar_url?: string;
}
@@ -3951,7 +3952,6 @@ export interface RateLimitConfig {
* required by the frontend.
*/
export interface ReducedUser extends MinimalUser {
- readonly name?: string;
readonly email: string;
readonly created_at: string;
readonly updated_at: string;
diff --git a/vpn/client_test.go b/vpn/client_test.go
index dd359afd0a..396f9b6762 100644
--- a/vpn/client_test.go
+++ b/vpn/client_test.go
@@ -102,6 +102,7 @@ func TestClient_WorkspaceUpdates(t *testing.T) {
MinimalUser: codersdk.MinimalUser{
ID: userID,
Username: "rootbeer",
+ Name: "Root Beer",
},
},
})