Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
cbdde3a
feat(seer): Gate agent chat messages on Seer credits
srest2021 Nov 6, 2026
c247328
feat(seer): Check Seer credits before Autofix steps and Open PR
srest2021 Nov 6, 2026
12cebaf
feat(seer): Handle SeerOutOfCreditsException at Autofix callers
srest2021 Nov 6, 2026
e2855ba
ref(seer): Keep the token-billed check inside can_run_seer_operation
srest2021 Nov 6, 2026
33f5287
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
d70d6cb
ref(seer): Split has_enough_seer_credits out of can_run_seer_operation
srest2021 Nov 6, 2026
56c7833
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
58a1b63
ref(seer): Combine the credit check flag conditions
srest2021 Nov 6, 2026
8856cd4
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
da71d66
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
c49f7ed
Merge remote-tracking branch 'origin/master' into srest2021/CW-3061-a…
srest2021 Nov 6, 2026
8e5ca8f
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
d2ef51a
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
0ab3b10
feat(seer): Check Seer credits before replying to an Autofix single run
srest2021 Nov 6, 2026
5cecd74
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
8552e64
feat(seer): Return 402 when a single run reply is out of credits
srest2021 Nov 6, 2026
69f5488
Merge remote-tracking branch 'origin/master' into srest2021/CW-3061-a…
srest2021 Nov 6, 2026
0f648e8
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
a3dae0d
ref(seer): Check the credit check flag first
srest2021 Nov 6, 2026
f738ddf
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
bdac9ed
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
94b979c
test(seer): Align credit check tests with their files
srest2021 Nov 6, 2026
302de4f
Merge branch 'srest2021/CW-3061-agent-chat' into srest2021/CW-3061-au…
srest2021 Nov 6, 2026
eae815f
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
0ec42da
Merge remote-tracking branch 'origin/master' into srest2021/CW-3061-a…
srest2021 Nov 6, 2026
6f7cb6f
ref(seer): Leave single run replies out of credit gating
srest2021 Nov 6, 2026
52c156d
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
9248e4c
Revert "feat(seer): Return 402 when a single run reply is out of cred…
srest2021 Nov 6, 2026
e35a52c
cleaning up diff
srest2021 Nov 6, 2026
99eb2ac
fix(seer): Don't let API callers claim the agentic triage referrer
srest2021 Nov 6, 2026
b8824e4
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
e8f415e
ref(seer): Clarify why the endpoint ignores the agentic triage referrer
srest2021 Nov 6, 2026
a1a9540
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
396779d
feat(seer): Check Seer credits before replying to an Autofix single run
srest2021 Nov 6, 2026
783742c
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
3c0d97b
feat(seer): Return 402 when a single run reply is out of credits
srest2021 Nov 6, 2026
90c5db5
cleaning up diff
srest2021 Nov 6, 2026
ff4faae
ref(seer): Restore the billing comment in trigger_autofix_agent
srest2021 Nov 6, 2026
f7c9960
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
2b31435
fix comment
srest2021 Nov 6, 2026
b86335d
cleaning up
srest2021 Nov 6, 2026
245aca9
fix ordering
srest2021 Nov 6, 2026
80bba23
Restore comment
srest2021 Nov 6, 2026
914a60c
ref(seer): Keep all billing skip rules in check_autofix_billing
srest2021 Nov 6, 2026
df89e79
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
28e5990
refactor billing helper
srest2021 Nov 6, 2026
766bc10
move logs out of helper
srest2021 Nov 6, 2026
6c0043d
small test fix:
srest2021 Nov 6, 2026
1c7c190
cleaning up tests
srest2021 Nov 6, 2026
a502768
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 6, 2026
8a11dd1
feat(seer-billing): Check Seer credits before queueing UI PR feedback
srest2021 Nov 6, 2026
c787f4d
fix(seer-billing): Don't pause PR iteration when a retry is out of cr…
srest2021 Nov 6, 2026
4e289d3
Merge remote-tracking branch 'origin/master' into srest2021/CW-3061-a…
srest2021 Nov 7, 2026
21285b1
Merge branch 'srest2021/CW-3061-autofix-gating' into srest2021/CW-306…
srest2021 Nov 7, 2026
451f3bd
ref(seer-billing): Pass organization to check_autofix_billing
sentry-junior[bot] Nov 9, 2026
ab0d0aa
ref(seer-billing): Check Autofix billing only in dispatch
srest2021 Nov 9, 2026
f271a38
improve pr iteration behavior
srest2021 Nov 9, 2026
89bdfdc
ref(seer-billing): Drop the agentic triage referrer exemption
srest2021 Nov 9, 2026
5b62f64
feat(seer-billing): Skip credit checks on runs agentic triage starts
srest2021 Nov 10, 2026
02aff6c
ref(seer-billing): Read the run's feature from rows already loaded
srest2021 Nov 10, 2026
a0b6046
clean up
srest2021 Nov 10, 2026
36fa96c
ref(seer-billing): Derive is_new_run from the run lookup
srest2021 Nov 10, 2026
8888ed6
Merge remote-tracking branch 'origin/srest2021/CW-3061-autofix-gating…
srest2021 Nov 10, 2026
6caa50a
Merge remote-tracking branch 'origin/srest2021/CW-3061-autofix-out-of…
srest2021 Nov 10, 2026
d15d1c0
feat(seer-billing): Skip the PR feedback credit check on agentic tria…
srest2021 Nov 10, 2026
40643f0
Merge remote-tracking branch 'origin/master' into srest2021/CW-3061-a…
srest2021 Nov 10, 2026
2f524d8
feat(seer-billing): Read the billing feature from Seer's run state
srest2021 Nov 10, 2026
1f348ba
minimize diff
srest2021 Nov 10, 2026
98d9acc
fix tests
srest2021 Nov 10, 2026
58d915c
cut scope
srest2021 Nov 10, 2026
503c370
Merge remote-tracking branch 'origin/sehrm/attribute-slack-seer-agent…
srest2021 Nov 11, 2026
f8c8047
ref(seer-billing): Build on the shared billing attribution sender
srest2021 Nov 11, 2026
ab2eb19
ref(seer-billing): Move the token-billed post-process skip to its own PR
sentry-junior[bot] Nov 11, 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
15 changes: 12 additions & 3 deletions src/sentry/seer/autofix/autofix_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
AutofixFeatureArgs,
autofix_run_targets_other_issue,
check_autofix_billing,
get_run_billing_feature,
require_autofix_run_for_group,
trigger_autofix_feature,
)
Expand Down Expand Up @@ -438,6 +439,7 @@ def trigger_autofix_agent(
group: Group,
step: AutofixStep,
referrer: AutofixReferrer,
*,
run_id: int | None = None,
stopping_point: AutofixStoppingPoint | None = None,
user_context: str | None = None,
Expand All @@ -458,6 +460,8 @@ def trigger_autofix_agent(
group: The Sentry group (issue) to analyze
step: Which autofix step to run
run_id: Existing run ID to continue, or None for new run
billing_feature: Internal-only. The feature the run is billed to for its whole life.
Not exposed via the API.
stopping_point: Where to stop the automated pipeline (only used for new runs)
allow_free_cohort: Internal-only flag set by agentic triage to bypass
quota for free cohort orgs. Not exposed via the API.
Expand Down Expand Up @@ -498,9 +502,9 @@ def trigger_autofix_agent(
args = AutofixFeatureArgs(
step=step,
referrer=referrer,
step_args=step_args,
existing_run_id=run_id,
insert_index=insert_index,
step_args=step_args,
user_context=user_context,
stopping_point=stopping_point,
allow_free_cohort=allow_free_cohort,
Expand Down Expand Up @@ -835,15 +839,20 @@ def trigger_push_changes(
):
raise PermissionDenied("Code generation is disabled for this organization")

check_autofix_billing(group.organization, SeerOperation.AUTOFIX_OPEN_PR, is_new_run=False)

client = get_autofix_agent_client(group, user=user)

if state is None:
state = _get_group_run_state(client, group, run_id)
else:
_validate_run_belongs_to_group(state, group)

check_autofix_billing(
group.organization,
get_run_billing_feature(state),
SeerOperation.AUTOFIX_OPEN_PR,
is_new_run=False,
)

record_autofix_event(
AiAutofixPrCreatedStartedEvent(
organization_id=group.organization.id,
Expand Down
47 changes: 34 additions & 13 deletions src/sentry/seer/autofix/feature/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from sentry.models.organization import Organization
from sentry.models.project import Project
from sentry.seer.agent.client import SeerAgentClient
from sentry.seer.agent.client_models import SeerRunState
from sentry.seer.agent.client_utils import (
AgentRunOptions,
collect_user_org_context,
Expand All @@ -43,7 +44,7 @@
get_automation_handoff,
is_free_cohort_org,
)
from sentry.seer.credits import SeerFeature, SeerOperation, has_enough_seer_credits
from sentry.seer.credits import SeerOperation, has_enough_seer_credits
from sentry.seer.models.run import SeerAgentRun, SeerRun
from sentry.seer.models.seer_api_models import UNKNOWN_RUN_ID_FOR_GROUP, SeerPermissionError
from sentry.users.models.user import User
Expand Down Expand Up @@ -88,6 +89,12 @@ def _mirror_matches_issue(group: Group) -> Q:
return Q(group_id=group.id, project_id=group.project_id)


def get_run_billing_feature(state: SeerRunState) -> int:
"""The billable feature the run was started under. Runs from before Seer
stored it are unattributed."""
return state.billing_feature or billing.SEER_BILLING_FEATURE_UNSPECIFIED


def autofix_run_targets_other_issue(group: Group, run_id: int) -> bool:
"""True unless ``run_id`` is mirrored to this issue's group and project.

Expand Down Expand Up @@ -162,21 +169,22 @@ def _org_allows_coding(group: Group) -> bool:

def check_autofix_billing(
organization: Organization,
billing_feature: int,
operation: SeerOperation,
*,
is_new_run: bool,
skip_quota_for_free_cohort: bool = False,
) -> bool:
"""
Raise if the organization can't pay for the operation. Token-billed orgs are
checked for credits, and everyone else is checked for quota once per run.
Returns whether the operation uses quota.
checked for credits under the run's billing feature, and everyone else is checked for
quota once per run. Returns whether the operation uses quota.
"""
# Check credits for token-billed orgs.
if features.has("organizations:token-billed-seer-enabled", organization):
if features.has(
"organizations:seer-credit-checks", organization
) and not has_enough_seer_credits(organization, SeerFeature.AUTOFIX, operation):
) and not has_enough_seer_credits(organization, billing_feature, operation):
raise SeerOutOfCreditsException()
return False

Expand All @@ -198,14 +206,16 @@ def continue_single_run(
group: Group,
reply: str,
*,
referrer: AutofixReferrer,
billing_feature: int,
user: User | RpcUser,
can_publish: bool,
referrer: AutofixReferrer,
) -> SeerRun:
from sentry.seer.autofix.on_completion_hook import AutofixOnCompletionHook

check_autofix_billing(
group.organization,
billing_feature,
SeerOperation.AUTOFIX_SINGLE_RUN_REPLY,
is_new_run=False,
)
Expand Down Expand Up @@ -259,10 +269,26 @@ def trigger_autofix_feature(
# Avoid a circular import through the legacy Autofix dispatcher.
from sentry.seer.autofix.on_completion_hook import AutofixOnCompletionHook

is_new_run = args.existing_run_id is None
existing_agent_run: SeerAgentRun | None = None
if args.existing_run_id is not None:
existing_agent_run = require_autofix_run_for_group(group, args.existing_run_id)
is_new_run = existing_agent_run is None

billing_feature = args.billing_feature
if billing_feature is None:
# Continuations without the stored feature are unattributed rather than guessed.
billing_feature = (
_BILLING_FEATURE_BY_REFERRER.get(
args.referrer, billing.SEER_BILLING_FEATURE_AUTOFIX_HEADLESS
)
if is_new_run
else billing.SEER_BILLING_FEATURE_UNSPECIFIED
)

try:
uses_quota = check_autofix_billing(
group.organization,
billing_feature,
args.step.seer_operation,
is_new_run=is_new_run,
# Free cohort orgs bypass quota only when called from agentic triage
Expand Down Expand Up @@ -382,10 +408,7 @@ def trigger_autofix_feature(
if is_new_run:
run = client.start_feature_run(
feature_id=SINGLE_RUN_FEATURE_ID if single_run else FEATURE_ID,
billing_feature=args.billing_feature
or _BILLING_FEATURE_BY_REFERRER.get(
args.referrer, billing.SEER_BILLING_FEATURE_AUTOFIX_HEADLESS
),
billing_feature=billing_feature,
payload=payload.dict(),
referrer=args.referrer.value,
user_org_context=user_org_context,
Expand All @@ -395,9 +418,7 @@ def trigger_autofix_feature(
flush=args.flush,
extras=extras,
)
elif args.existing_run_id is not None:
existing_agent_run = require_autofix_run_for_group(group, args.existing_run_id)

elif existing_agent_run is not None:
run = client.continue_feature_run(
existing_agent_run=existing_agent_run,
payload=payload.dict(),
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/seer/autofix/on_completion_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from sentry.seer.autofix.coding_agent import IntegrationNotFound
from sentry.seer.autofix.constants import AutofixReferrer
from sentry.seer.autofix.exceptions import SeerOutOfCreditsException
from sentry.seer.autofix.feature.dispatch import get_run_billing_feature
from sentry.seer.autofix.feature.models import FEATURE_ID as AUTOFIX_FEATURE_ID
from sentry.seer.autofix.feature.models import LEGACY_FEATURE_ID as LEGACY_AUTOFIX_FEATURE_ID
from sentry.seer.autofix.pr_iteration.completion import (
Expand Down Expand Up @@ -793,6 +794,7 @@ def _maybe_continue_pipeline(
step=next_step,
referrer=referrer,
run_id=run_id,
billing_feature=get_run_billing_feature(state),
)
except SeerOutOfCreditsException:
logger.info(
Expand Down
7 changes: 6 additions & 1 deletion src/sentry/seer/autofix/pr_iteration/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
from sentry.seer.autofix.commit_author import SeerCommitAuthor, parse_commit_author
from sentry.seer.autofix.constants import AutofixReferrer
from sentry.seer.autofix.exceptions import SeerOutOfCreditsException
from sentry.seer.autofix.feature.dispatch import AutofixFeatureArgs, trigger_autofix_feature
from sentry.seer.autofix.feature.dispatch import (
AutofixFeatureArgs,
get_run_billing_feature,
trigger_autofix_feature,
)
from sentry.seer.autofix.feature.models import PrIterationStepArgs
from sentry.seer.autofix.pr_iteration.current_iteration import triggered_iteration_id
from sentry.seer.autofix.pr_iteration.emit import (
Expand Down Expand Up @@ -582,6 +586,7 @@ def _retry_push_on_moved_branch(
pr.repo_name: pr.pr_url for pr in state.repo_pr_states.values() if pr.pr_url
},
),
billing_feature=get_run_billing_feature(state),
),
)
except SeerOutOfCreditsException:
Expand Down
5 changes: 3 additions & 2 deletions src/sentry/seer/autofix/pr_iteration/manual_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
from sentry.models.group import Group
from sentry.seer.autofix.autofix_agent import get_autofix_run_state
from sentry.seer.autofix.constants import AutofixReferrer
from sentry.seer.autofix.feature.dispatch import get_run_billing_feature
from sentry.seer.autofix.pr_iteration.emit import bootstrap_iteration
from sentry.seer.autofix.pr_iteration.feedback import Feedback
from sentry.seer.autofix.pr_iteration.feedback_sources.base import ConsumeTriggerSource
from sentry.seer.autofix.pr_iteration.pause import PauseReason, get_pause_reason
from sentry.seer.autofix.pr_iteration.queue import enqueue_autofix_feedback
from sentry.seer.credits import SeerFeature, SeerOperation, can_run_seer_operation
from sentry.seer.credits import SeerOperation, can_run_seer_operation
from sentry.seer.endpoints.utils import (
SEER_AUTOFIX_CONTINUE_OUT_OF_CREDITS_DETAIL,
SEER_OUT_OF_CREDITS_CODE,
Expand Down Expand Up @@ -88,7 +89,7 @@ def handle_ui_feedback(

# Check credits here, since the queued feedback is consumed after this request returns.
if not can_run_seer_operation(
group.organization, SeerFeature.AUTOFIX, SeerOperation.AUTOFIX_PR_ITERATION
group.organization, get_run_billing_feature(run_state), SeerOperation.AUTOFIX_PR_ITERATION
):
return Response(
{
Expand Down
31 changes: 22 additions & 9 deletions src/sentry/seer/credits.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from collections.abc import Callable
from enum import StrEnum

from sentry_protos.billing.v1.common.v1.seer_billing_feature_pb2 import (
SEER_BILLING_FEATURE_UNSPECIFIED,
SeerBillingFeature,
)
from sentry_protos.billing.v1.services.seer_feature_billing.v1.endpoint_check_seer_credits_pb2 import (
CheckSeerCreditsRequest,
)
Expand All @@ -21,11 +25,18 @@ class SeerOperation(StrEnum):
AUTOFIX_SINGLE_RUN_REPLY = "autofix_single_run_reply"


class SeerFeature(StrEnum):
"""Seer features as tagged on LLM proxy calls, which billing maps to data categories."""

AUTOFIX = "autofix"
EXPLORER = "explorer"
def billing_feature_label(feature: int) -> str:
"""
The label LLM proxy usage and billing use for a SeerBillingFeature value: the enum name,
lowercased, without its prefix. Missing attribution is "unattributed", like the LLM proxy.
"""
if feature == SEER_BILLING_FEATURE_UNSPECIFIED:
return "unattributed"
return (
SeerBillingFeature.Name(SeerBillingFeature.ValueType(feature))
.removeprefix("SEER_BILLING_FEATURE_")
.lower()
)


# TODO(CW-2314): Fake value until we have real estimates.
Expand All @@ -46,7 +57,7 @@ class SeerFeature(StrEnum):


def has_enough_seer_credits(
organization: Organization, feature: SeerFeature, operation: SeerOperation
organization: Organization, feature: int, operation: SeerOperation
) -> bool:
"""
Checks whether the organization has enough Seer credits to run the operation,
Expand All @@ -55,7 +66,7 @@ def has_enough_seer_credits(
response = seer_credit.backend.check_seer_credits(
CheckSeerCreditsRequest(
organization_id=organization.id,
feature_id=feature.value,
feature_id=billing_feature_label(feature),
predicted_credit_usage=SEER_OPERATION_ESTIMATES[operation](),
take_lease=False,
)
Expand All @@ -64,9 +75,11 @@ def has_enough_seer_credits(


def can_run_seer_operation(
organization: Organization, feature: SeerFeature, operation: SeerOperation
organization: Organization, feature: int, operation: SeerOperation
) -> bool:
"""Checks whether the organization is token-billed and has enough Seer credits to run the operation."""
"""
Checks whether the organization is token-billed and has enough Seer credits to run the operation.
"""
if not features.has("organizations:seer-credit-checks", organization) or not features.has(
"organizations:token-billed-seer-enabled", organization
):
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/seer/endpoints/admin_autofix_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
)
from sentry.seer.autofix.constants import AutofixReferrer
from sentry.seer.autofix.exceptions import SeerOutOfCreditsException
from sentry.seer.autofix.feature.dispatch import get_run_billing_feature
from sentry.seer.autofix.feature.models import FEATURE_ID, LEGACY_FEATURE_ID
from sentry.seer.autofix.on_completion_hook import PIPELINE_ORDER
from sentry.seer.models import SeerRun
Expand Down Expand Up @@ -119,6 +120,7 @@ def _retry_run(organization: Organization, run_id: int) -> dict[str, Any]:
step=step,
referrer=step_referrer or run_referrer or AutofixReferrer.UNKNOWN,
run_id=run_id,
billing_feature=get_run_billing_feature(state),
insert_index=insert_index,
)
except SeerOutOfCreditsException:
Expand Down
12 changes: 9 additions & 3 deletions src/sentry/seer/endpoints/group_ai_autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@
from sentry.seer.autofix.commit_author import commit_author_for_user
from sentry.seer.autofix.constants import PUBLISH_SCOPES, AutofixReferrer
from sentry.seer.autofix.exceptions import NoSeerQuotaException, SeerOutOfCreditsException
from sentry.seer.autofix.feature.dispatch import project_stopping_point, should_use_single_run
from sentry.seer.autofix.feature.dispatch import (
get_run_billing_feature,
project_stopping_point,
should_use_single_run,
)
from sentry.seer.autofix.feature.models import FEATURE_ID as AUTOFIX_FEATURE_ID
from sentry.seer.autofix.feature.models import SINGLE_RUN_FEATURE_ID
from sentry.seer.autofix.on_completion_hook import get_run_stopping_point
Expand Down Expand Up @@ -514,13 +518,16 @@ def post(
status=status.HTTP_409_CONFLICT,
)

# The client can supply referrer. Resolve attribution from the request instead.
billing_feature: int = billing.SEER_BILLING_FEATURE_AUTOFIX_HEADLESS
if resolved_run_id is not None:
try:
run_state = get_autofix_run_state(group, resolved_run_id)
except SeerPermissionError as e:
if _is_unknown_run_id_error(e):
return Response(status=status.HTTP_404_NOT_FOUND)
raise PermissionDenied(SEER_PERMISSION_DENIED)
billing_feature = get_run_billing_feature(run_state)

# A continued run keeps the stopping point it started with, and the
# completion hook acts on it after this step, so gate on it too.
Expand Down Expand Up @@ -562,8 +569,6 @@ def post(
status=status.HTTP_409_CONFLICT,
)

# The client can supply referrer. Resolve attribution from the request instead.
billing_feature = billing.SEER_BILLING_FEATURE_AUTOFIX_HEADLESS
if is_autofix_kickoff:
actor = resolve_action_actor(request)
source = resolve_action_source(request)
Expand Down Expand Up @@ -721,6 +726,7 @@ def get(self, request: Request, group: Group) -> Response[AutofixStateResponse]:
else AUTOFIX_FEATURE_ID,
"status": state.status,
"failure_reason": state.failure_reason,
"billing_feature": state.billing_feature,
"blocks": blocks,
"updated_at": state.updated_at,
"pending_user_input": (
Expand Down
Loading
Loading