diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden
index 0124c4f32846b..37e1b27e19907 100644
--- a/cli/testdata/coder_server_--help.golden
+++ b/cli/testdata/coder_server_--help.golden
@@ -158,6 +158,14 @@ AI BRIDGE OPTIONS:
Maximum number of AI Bridge requests per second per replica. Set to 0
to disable (unlimited).
+ --aibridge-send-actor-headers bool, $CODER_AIBRIDGE_SEND_ACTOR_HEADERS (default: false)
+ Once enabled, extra headers will be added to upstream requests to
+ identify the user (actor) making requests to AI Bridge. This is only
+ needed if you are using a proxy between AI Bridge and an upstream AI
+ provider. This will send X-Ai-Bridge-Actor-Id (the ID of the user
+ making the request) and X-Ai-Bridge-Actor-Metadata-Username (their
+ username).
+
--aibridge-structured-logging bool, $CODER_AIBRIDGE_STRUCTURED_LOGGING (default: false)
Emit structured logs for AI Bridge interception records. Use this for
exporting these records to external SIEM or observability systems.
diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden
index 25ff00741d287..5504fdadc901f 100644
--- a/cli/testdata/server-config.yaml.golden
+++ b/cli/testdata/server-config.yaml.golden
@@ -782,6 +782,13 @@ aibridge:
# these records to external SIEM or observability systems.
# (default: false, type: bool)
structuredLogging: false
+ # Once enabled, extra headers will be added to upstream requests to identify the
+ # user (actor) making requests to AI Bridge. This is only needed if you are using
+ # a proxy between AI Bridge and an upstream AI provider. This will send
+ # X-Ai-Bridge-Actor-Id (the ID of the user making the request) and
+ # X-Ai-Bridge-Actor-Metadata-Username (their username).
+ # (default: false, type: bool)
+ send_actor_headers: false
# Enable the circuit breaker to protect against cascading failures from upstream
# AI provider rate limits (429, 503, 529 overloaded).
# (default: false, type: bool)
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index 1701d91d2f470..e0152f9ed97a0 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -12075,6 +12075,9 @@ const docTemplate = `{
"retention": {
"type": "integer"
},
+ "send_actor_headers": {
+ "type": "boolean"
+ },
"structured_logging": {
"type": "boolean"
}
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 75bcaab60e3d3..6eb0ad586821b 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -10727,6 +10727,9 @@
"retention": {
"type": "integer"
},
+ "send_actor_headers": {
+ "type": "boolean"
+ },
"structured_logging": {
"type": "boolean"
}
diff --git a/codersdk/deployment.go b/codersdk/deployment.go
index fa103750db812..54e29e98822d2 100644
--- a/codersdk/deployment.go
+++ b/codersdk/deployment.go
@@ -3509,6 +3509,18 @@ Write out the current server config as YAML to stdout.`,
Group: &deploymentGroupAIBridge,
YAML: "structuredLogging",
},
+ {
+ Name: "AI Bridge Send Actor Headers",
+ Description: "Once enabled, extra headers will be added to upstream requests to identify the user (actor) making requests to AI Bridge. " +
+ "This is only needed if you are using a proxy between AI Bridge and an upstream AI provider. " +
+ "This will send X-Ai-Bridge-Actor-Id (the ID of the user making the request) and X-Ai-Bridge-Actor-Metadata-Username (their username).",
+ Flag: "aibridge-send-actor-headers",
+ Env: "CODER_AIBRIDGE_SEND_ACTOR_HEADERS",
+ Value: &c.AI.BridgeConfig.SendActorHeaders,
+ Default: "false",
+ Group: &deploymentGroupAIBridge,
+ YAML: "send_actor_headers",
+ },
{
Name: "AI Bridge Circuit Breaker Enabled",
Description: "Enable the circuit breaker to protect against cascading failures from upstream AI provider rate limits (429, 503, 529 overloaded).",
@@ -3722,6 +3734,7 @@ type AIBridgeConfig struct {
MaxConcurrency serpent.Int64 `json:"max_concurrency" typescript:",notnull"`
RateLimit serpent.Int64 `json:"rate_limit" typescript:",notnull"`
StructuredLogging serpent.Bool `json:"structured_logging" typescript:",notnull"`
+ SendActorHeaders serpent.Bool `json:"send_actor_headers" typescript:",notnull"`
// Circuit breaker protects against cascading failures from upstream AI
// provider rate limits (429, 503, 529 overloaded).
CircuitBreakerEnabled serpent.Bool `json:"circuit_breaker_enabled" typescript:",notnull"`
diff --git a/docs/reference/api/general.md b/docs/reference/api/general.md
index 5300a38444d0c..f0ac2d64c9527 100644
--- a/docs/reference/api/general.md
+++ b/docs/reference/api/general.md
@@ -200,6 +200,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
},
"rate_limit": 0,
"retention": 0,
+ "send_actor_headers": true,
"structured_logging": true
}
},
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index 32f02821154ee..94e8d79b82979 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -405,6 +405,7 @@
},
"rate_limit": 0,
"retention": 0,
+ "send_actor_headers": true,
"structured_logging": true
}
```
@@ -426,6 +427,7 @@
| `openai` | [codersdk.AIBridgeOpenAIConfig](#codersdkaibridgeopenaiconfig) | false | | |
| `rate_limit` | integer | false | | |
| `retention` | integer | false | | |
+| `send_actor_headers` | boolean | false | | |
| `structured_logging` | boolean | false | | |
## codersdk.AIBridgeInterception
@@ -771,6 +773,7 @@
},
"rate_limit": 0,
"retention": 0,
+ "send_actor_headers": true,
"structured_logging": true
}
}
@@ -2695,6 +2698,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
},
"rate_limit": 0,
"retention": 0,
+ "send_actor_headers": true,
"structured_logging": true
}
},
@@ -3248,6 +3252,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
},
"rate_limit": 0,
"retention": 0,
+ "send_actor_headers": true,
"structured_logging": true
}
},
diff --git a/docs/reference/cli/server.md b/docs/reference/cli/server.md
index b5d5bcb381e3f..7b8ebdd67ec88 100644
--- a/docs/reference/cli/server.md
+++ b/docs/reference/cli/server.md
@@ -1857,6 +1857,17 @@ Maximum number of AI Bridge requests per second per replica. Set to 0 to disable
Emit structured logs for AI Bridge interception records. Use this for exporting these records to external SIEM or observability systems.
+### --aibridge-send-actor-headers
+
+| | |
+|-------------|-------------------------------------------------|
+| Type | bool |
+| Environment | $CODER_AIBRIDGE_SEND_ACTOR_HEADERS |
+| YAML | aibridge.send_actor_headers |
+| Default | false |
+
+Once enabled, extra headers will be added to upstream requests to identify the user (actor) making requests to AI Bridge. This is only needed if you are using a proxy between AI Bridge and an upstream AI provider. This will send X-Ai-Bridge-Actor-Id (the ID of the user making the request) and X-Ai-Bridge-Actor-Metadata-Username (their username).
+
### --aibridge-circuit-breaker-enabled
| | |
diff --git a/enterprise/aibridged/aibridged_test.go b/enterprise/aibridged/aibridged_test.go
index 6e0bebb7ad768..dbba210091ae5 100644
--- a/enterprise/aibridged/aibridged_test.go
+++ b/enterprise/aibridged/aibridged_test.go
@@ -17,6 +17,7 @@ import (
"cdr.dev/slog/v3/sloggers/slogtest"
"github.com/coder/aibridge"
+ "github.com/coder/aibridge/intercept"
agplaibridge "github.com/coder/coder/v2/coderd/aibridge"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/aibridged"
@@ -312,6 +313,105 @@ func (h *mockHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
_, _ = rw.Write([]byte(r.URL.Path))
}
+// TestServeHTTP_ActorHeaders validates that actor headers are correctly forwarded to
+// upstream AI providers when SendActorHeaders is enabled in the provider configuration.
+// These headers allow upstream providers to identify the user making the request for
+// tracking and auditing purposes.
+func TestServeHTTP_ActorHeaders(t *testing.T) {
+ t.Parallel()
+
+ testUsername := "testuser"
+ testUserID := uuid.New()
+
+ cases := []struct {
+ path string
+ }{
+ // Not a complete set of paths; we're not testing the specific APIs - just the provider configs.
+ {
+ path: "/openai/v1/chat/completions",
+ },
+ {
+ path: "/anthropic/v1/messages",
+ },
+ }
+
+ for _, tc := range cases {
+ t.Run(tc.path, func(t *testing.T) {
+ t.Parallel()
+
+ // Setup mock upstream AI server that captures headers.
+ var receivedHeaders http.Header
+ upstreamSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ receivedHeaders = r.Header.Clone()
+ w.WriteHeader(http.StatusTeapot)
+ _, _ = w.Write([]byte(`i am a teapot`))
+ }))
+ t.Cleanup(upstreamSrv.Close)
+
+ // Setup with SendActorHeaders enabled.
+ logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
+ ctrl := gomock.NewController(t)
+ client := mock.NewMockDRPCClient(ctrl)
+
+ // Create providers with SendActorHeaders=true.
+ providers := []aibridge.Provider{
+ aibridge.NewOpenAIProvider(aibridge.OpenAIConfig{
+ BaseURL: upstreamSrv.URL,
+ SendActorHeaders: true,
+ }),
+ aibridge.NewAnthropicProvider(aibridge.AnthropicConfig{
+ BaseURL: upstreamSrv.URL,
+ SendActorHeaders: true,
+ }, nil),
+ }
+
+ pool, err := aibridged.NewCachedBridgePool(aibridged.DefaultPoolOptions, providers, logger, nil, testTracer)
+ require.NoError(t, err)
+ conn := &mockDRPCConn{}
+ client.EXPECT().DRPCConn().AnyTimes().Return(conn)
+
+ // Return authorization response with user ID and username.
+ client.EXPECT().IsAuthorized(gomock.Any(), gomock.Any()).AnyTimes().Return(&proto.IsAuthorizedResponse{
+ OwnerId: testUserID.String(),
+ Username: testUsername,
+ }, nil)
+ client.EXPECT().GetMCPServerConfigs(gomock.Any(), gomock.Any()).AnyTimes().Return(&proto.GetMCPServerConfigsResponse{}, nil)
+ client.EXPECT().RecordInterception(gomock.Any(), gomock.Any()).AnyTimes().Return(&proto.RecordInterceptionResponse{}, nil)
+ client.EXPECT().RecordInterceptionEnded(gomock.Any(), gomock.Any()).AnyTimes()
+
+ // Given: aibridged is started.
+ srv, err := aibridged.New(t.Context(), pool, func(ctx context.Context) (aibridged.DRPCClient, error) {
+ return client, nil
+ }, logger, testTracer)
+ require.NoError(t, err, "create new aibridged")
+ t.Cleanup(func() {
+ _ = srv.Shutdown(testutil.Context(t, testutil.WaitShort))
+ })
+
+ // When: a request is made to aibridged.
+ ctx := testutil.Context(t, testutil.WaitShort)
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, tc.path, bytes.NewBufferString(`{}`))
+ require.NoError(t, err, "make request to test server")
+ req.Header.Add("Authorization", "Bearer key")
+ req.Header.Add("Accept", "application/json")
+
+ // When: aibridged handles the request.
+ rec := httptest.NewRecorder()
+ srv.ServeHTTP(rec, req)
+
+ // Then: the actor headers should be present in the upstream request.
+ require.NotEmpty(t, receivedHeaders, "upstream server should have received headers")
+
+ // Verify the actor ID header is present with the correct value.
+ actorIDHeader := receivedHeaders.Get(intercept.ActorIDHeader())
+ assert.Equal(t, testUserID.String(), actorIDHeader, "actor ID header should contain user ID")
+ // Verify the actor metadata header for username is present.
+ usernameHeader := receivedHeaders.Get(intercept.ActorMetadataHeader("Username"))
+ assert.Equal(t, testUsername, usernameHeader, "actor metadata username header should contain username")
+ })
+ }
+}
+
// TestRouting validates that a request which originates with aibridged will be handled
// by coder/aibridge's handling logic in a provider-specific manner.
// We must validate that logic that pertains to coder/coder is exercised.
diff --git a/enterprise/aibridged/http.go b/enterprise/aibridged/http.go
index 087702be0354d..5693a7c4139b5 100644
--- a/enterprise/aibridged/http.go
+++ b/enterprise/aibridged/http.go
@@ -9,6 +9,7 @@ import (
"cdr.dev/slog/v3"
"github.com/coder/aibridge"
+ "github.com/coder/aibridge/recorder"
agplaibridge "github.com/coder/coder/v2/coderd/aibridge"
"github.com/coder/coder/v2/enterprise/aibridged/proto"
)
@@ -61,7 +62,13 @@ func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
}
// Rewire request context to include actor.
- r = r.WithContext(aibridge.AsActor(ctx, resp.GetOwnerId(), nil))
+ //
+ // [NOTE]
+ // The metadata provided here must NOT be sensitive as it could be included
+ // in requests to upstream services.
+ r = r.WithContext(aibridge.AsActor(ctx, resp.GetOwnerId(), recorder.Metadata{
+ "Username": resp.GetUsername(),
+ }))
id, err := uuid.Parse(resp.GetOwnerId())
if err != nil {
diff --git a/enterprise/aibridged/proto/aibridged.pb.go b/enterprise/aibridged/proto/aibridged.pb.go
index 09c6f4eb8e5f4..08b2af7312e10 100644
--- a/enterprise/aibridged/proto/aibridged.pb.go
+++ b/enterprise/aibridged/proto/aibridged.pb.go
@@ -978,6 +978,7 @@ type IsAuthorizedResponse struct {
OwnerId string `protobuf:"bytes,1,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"`
ApiKeyId string `protobuf:"bytes,2,opt,name=api_key_id,json=apiKeyId,proto3" json:"api_key_id,omitempty"`
+ Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
}
func (x *IsAuthorizedResponse) Reset() {
@@ -1026,6 +1027,13 @@ func (x *IsAuthorizedResponse) GetApiKeyId() string {
return ""
}
+func (x *IsAuthorizedResponse) GetUsername() string {
+ if x != nil {
+ return x.Username
+ }
+ return ""
+}
+
var File_enterprise_aibridged_proto_aibridged_proto protoreflect.FileDescriptor
var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{
@@ -1206,64 +1214,66 @@ var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a, 0x13, 0x49, 0x73, 0x41, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
- 0x22, 0x4f, 0x0a, 0x14, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
+ 0x22, 0x6b, 0x0a, 0x14, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x49,
- 0x64, 0x32, 0xce, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59,
- 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
- 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63,
- 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
- 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f,
- 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63,
- 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45,
- 0x6e, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63,
- 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45,
- 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63,
- 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b,
- 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f,
- 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d,
- 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f,
- 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73,
- 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f,
- 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72,
- 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x32, 0xeb, 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
- 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50,
- 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76,
- 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53,
- 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65,
- 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73,
- 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65,
- 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
- 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43,
- 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b,
- 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x32, 0x55, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47,
- 0x0a, 0x0c, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
- 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f,
+ 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xce, 0x03,
+ 0x0a, 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65,
+ 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49,
+ 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72,
+ 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49,
+ 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64,
+ 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49,
+ 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x53, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73,
+ 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f,
+ 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f,
+ 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72,
+ 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73,
+ 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55,
+ 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f,
+ 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12,
+ 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f,
+ 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f,
+ 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb,
+ 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
+ 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65,
+ 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x7a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
+ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63,
+ 0x68, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65,
+ 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72,
+ 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42,
+ 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x55, 0x0a, 0x0a,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x49, 0x73,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75,
- 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65,
- 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x69, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49,
+ 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32,
+ 0x2f, 0x61, 0x69, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/enterprise/aibridged/proto/aibridged.proto b/enterprise/aibridged/proto/aibridged.proto
index c6c5abcff0410..09ea75f12328c 100644
--- a/enterprise/aibridged/proto/aibridged.proto
+++ b/enterprise/aibridged/proto/aibridged.proto
@@ -121,4 +121,5 @@ message IsAuthorizedRequest {
message IsAuthorizedResponse {
string owner_id = 1;
string api_key_id = 2;
+ string username = 3;
}
diff --git a/enterprise/aibridgedserver/aibridgedserver.go b/enterprise/aibridgedserver/aibridgedserver.go
index 8699b9c96b454..2a6b8b83a159f 100644
--- a/enterprise/aibridgedserver/aibridgedserver.go
+++ b/enterprise/aibridgedserver/aibridgedserver.go
@@ -505,6 +505,7 @@ func (s *Server) IsAuthorized(ctx context.Context, in *proto.IsAuthorizedRequest
return &proto.IsAuthorizedResponse{
OwnerId: key.UserID.String(),
ApiKeyId: key.ID,
+ Username: user.Username,
}, nil
}
diff --git a/enterprise/aibridgedserver/aibridgedserver_test.go b/enterprise/aibridgedserver/aibridgedserver_test.go
index 6f99810872338..efa2ae3ee6021 100644
--- a/enterprise/aibridgedserver/aibridgedserver_test.go
+++ b/enterprise/aibridgedserver/aibridgedserver_test.go
@@ -186,6 +186,7 @@ func TestAuthorization(t *testing.T) {
expected := proto.IsAuthorizedResponse{
OwnerId: user.ID.String(),
ApiKeyId: keyID,
+ Username: user.Username,
}
require.NoError(t, err)
require.Equal(t, &expected, resp)
diff --git a/enterprise/cli/aibridged.go b/enterprise/cli/aibridged.go
index e9bfce7cd01a1..62e6e74527f6f 100644
--- a/enterprise/cli/aibridged.go
+++ b/enterprise/cli/aibridged.go
@@ -21,30 +21,33 @@ func newAIBridgeDaemon(coderAPI *coderd.API) (*aibridged.Server, error) {
coderAPI.Logger.Debug(ctx, "starting in-memory aibridge daemon")
logger := coderAPI.Logger.Named("aibridged")
+ cfg := coderAPI.DeploymentValues.AI.BridgeConfig
// Build circuit breaker config if enabled.
var cbConfig *config.CircuitBreaker
- if coderAPI.DeploymentValues.AI.BridgeConfig.CircuitBreakerEnabled.Value() {
+ if cfg.CircuitBreakerEnabled.Value() {
cbConfig = &config.CircuitBreaker{
- FailureThreshold: uint32(coderAPI.DeploymentValues.AI.BridgeConfig.CircuitBreakerFailureThreshold.Value()), //nolint:gosec // Validated by serpent.Validate in deployment options.
- Interval: coderAPI.DeploymentValues.AI.BridgeConfig.CircuitBreakerInterval.Value(),
- Timeout: coderAPI.DeploymentValues.AI.BridgeConfig.CircuitBreakerTimeout.Value(),
- MaxRequests: uint32(coderAPI.DeploymentValues.AI.BridgeConfig.CircuitBreakerMaxRequests.Value()), //nolint:gosec // Validated by serpent.Validate in deployment options.
+ FailureThreshold: uint32(cfg.CircuitBreakerFailureThreshold.Value()), //nolint:gosec // Validated by serpent.Validate in deployment options.
+ Interval: cfg.CircuitBreakerInterval.Value(),
+ Timeout: cfg.CircuitBreakerTimeout.Value(),
+ MaxRequests: uint32(cfg.CircuitBreakerMaxRequests.Value()), //nolint:gosec // Validated by serpent.Validate in deployment options.
}
}
// Setup supported providers with circuit breaker config.
providers := []aibridge.Provider{
aibridge.NewOpenAIProvider(aibridge.OpenAIConfig{
- BaseURL: coderAPI.DeploymentValues.AI.BridgeConfig.OpenAI.BaseURL.String(),
- Key: coderAPI.DeploymentValues.AI.BridgeConfig.OpenAI.Key.String(),
- CircuitBreaker: cbConfig,
+ BaseURL: cfg.OpenAI.BaseURL.String(),
+ Key: cfg.OpenAI.Key.String(),
+ CircuitBreaker: cbConfig,
+ SendActorHeaders: cfg.SendActorHeaders.Value(),
}),
aibridge.NewAnthropicProvider(aibridge.AnthropicConfig{
- BaseURL: coderAPI.DeploymentValues.AI.BridgeConfig.Anthropic.BaseURL.String(),
- Key: coderAPI.DeploymentValues.AI.BridgeConfig.Anthropic.Key.String(),
- CircuitBreaker: cbConfig,
- }, getBedrockConfig(coderAPI.DeploymentValues.AI.BridgeConfig.Bedrock)),
+ BaseURL: cfg.Anthropic.BaseURL.String(),
+ Key: cfg.Anthropic.Key.String(),
+ CircuitBreaker: cbConfig,
+ SendActorHeaders: cfg.SendActorHeaders.Value(),
+ }, getBedrockConfig(cfg.Bedrock)),
}
reg := prometheus.WrapRegistererWithPrefix("coder_aibridged_", coderAPI.PrometheusRegistry)
diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden
index 8dc28ffc7b8c8..4b1a1b2ddbfb8 100644
--- a/enterprise/cli/testdata/coder_server_--help.golden
+++ b/enterprise/cli/testdata/coder_server_--help.golden
@@ -159,6 +159,14 @@ AI BRIDGE OPTIONS:
Maximum number of AI Bridge requests per second per replica. Set to 0
to disable (unlimited).
+ --aibridge-send-actor-headers bool, $CODER_AIBRIDGE_SEND_ACTOR_HEADERS (default: false)
+ Once enabled, extra headers will be added to upstream requests to
+ identify the user (actor) making requests to AI Bridge. This is only
+ needed if you are using a proxy between AI Bridge and an upstream AI
+ provider. This will send X-Ai-Bridge-Actor-Id (the ID of the user
+ making the request) and X-Ai-Bridge-Actor-Metadata-Username (their
+ username).
+
--aibridge-structured-logging bool, $CODER_AIBRIDGE_STRUCTURED_LOGGING (default: false)
Emit structured logs for AI Bridge interception records. Use this for
exporting these records to external SIEM or observability systems.
diff --git a/go.mod b/go.mod
index 13f8ec270cc3c..689dbb2fc52a4 100644
--- a/go.mod
+++ b/go.mod
@@ -473,7 +473,7 @@ require (
github.com/anthropics/anthropic-sdk-go v1.19.0
github.com/brianvoe/gofakeit/v7 v7.14.0
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225
- github.com/coder/aibridge v0.3.1-0.20260121122740-e164b504fc52
+ github.com/coder/aibridge v0.3.1-0.20260126145207-bf1abce438e9
github.com/coder/aisdk-go v0.0.9
github.com/coder/boundary v0.6.0
github.com/coder/preview v1.0.4
diff --git a/go.sum b/go.sum
index df875709dbb07..bab5ceca9c061 100644
--- a/go.sum
+++ b/go.sum
@@ -927,8 +927,8 @@ github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4=
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8=
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4=
-github.com/coder/aibridge v0.3.1-0.20260121122740-e164b504fc52 h1:UcsOXQH881tXPpU75Cz4GpTmV7JTZ7GS8AdA0QdAAC4=
-github.com/coder/aibridge v0.3.1-0.20260121122740-e164b504fc52/go.mod h1:x45BE/NNDesDN1eWy4bsg81QsL6ou7xXPIeQr0ePETQ=
+github.com/coder/aibridge v0.3.1-0.20260126145207-bf1abce438e9 h1:aaqHxY6OX3ONle6bVUb6aSypLa+BvvBp24HbFRPKiEE=
+github.com/coder/aibridge v0.3.1-0.20260126145207-bf1abce438e9/go.mod h1:x45BE/NNDesDN1eWy4bsg81QsL6ou7xXPIeQr0ePETQ=
github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo=
github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M=
github.com/coder/boundary v0.6.0 h1:DfYVBIH8/6EBfg9I0qz7rX2jo+4blUx4P4amd13nib8=
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index a4c41ea053a38..da26b8e1de113 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -37,6 +37,7 @@ export interface AIBridgeConfig {
readonly max_concurrency: number;
readonly rate_limit: number;
readonly structured_logging: boolean;
+ readonly send_actor_headers: boolean;
/**
* Circuit breaker protects against cascading failures from upstream AI
* provider rate limits (429, 503, 529 overloaded).