Skip to content

Conversation

@whoAbhishekSah
Copy link
Member

Summary

Add InputHintOption struct and InputOptions field to support user-friendly option display in preference traits.

Changes

core/preference/preference.go

// New struct
type InputHintOption struct {
    Name  string  // Machine-readable identifier (e.g., "sq_km", "Mg")
    Title string  // User-friendly display (e.g., "Square Kilometers", "Megagram (Mg)")
}

// New field in Trait
InputOptions []InputHintOption  // Takes precedence over InputHints

core/preference/validator.go

  • Add NewSelectValidatorFromOptions() to validate against InputOptions names

Usage

input_options:
  - name: sq_km
    title: Square Kilometers
  - name: sq_ft
    title: Square Feet
default: sq_km

Dependencies

Next Steps

Once proton PR is merged:

  1. Regenerate proto stubs
  2. Update handler to transform InputOptions to proto

🤖 Generated with Claude Code

Add InputHintOption struct with name and title fields for user-friendly
option display. The InputOptions field in Trait allows specifying both
machine-readable names and display titles.

- Add InputHintOption struct
- Add InputOptions field to Trait (takes precedence over InputHints)
- Add NewSelectValidatorFromOptions function

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@vercel
Copy link

vercel bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Feb 11, 2026 9:35am

@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Structured selectable options (machine name + user-friendly title) for trait inputs; these take precedence over legacy hints.
    • Preferences now include a human-friendly value_title when an option title is available; loaders and create responses populate value_title.
    • Validation now validates structured input options for traits while preserving backward compatibility.
  • Documentation

    • API docs updated to expose input_options and value_title fields.

Walkthrough

Adds InputHintOption and InputOptions to Trait, Preference.ValueTitle, Trait.GetValueTitle, and NewSelectValidatorFromOptions; GetValidator now prefers InputOptions for select/combobox; service Create and LoadUserPreferences populate Preference.ValueTitle; API/schema and validation updated to include InputHintOption and value_title.

Changes

Cohort / File(s) Summary
Preference core
core/preference/preference.go
Added InputHintOption { Name, Title }; added Trait.InputOptions []InputHintOption and Preference.ValueTitle string; added Trait.GetValueTitle(value string) string; updated GetValidator() to prefer InputOptions for select/combobox inputs (falls back to InputHints).
Validator constructor
core/preference/validator.go
Added NewSelectValidatorFromOptions(options []InputHintOption) *SelectValidator which builds a SelectValidator from non-empty option Name values.
Service population
core/preference/service.go
Create now sets created.ValueTitle from the trait; LoadUserPreferences sets Preference.ValueTitle for existing and defaulted preferences using trait.GetValueTitle(...).
API schema & validation
proto/apidocs.swagger.yaml, proto/v1beta1/models.pb.validate.go
Added v1beta1InputHintOption type; added input_options to PreferenceTrait and value_title to Preference; generated validation methods/types for InputHintOption and integrated InputOptions validation into PreferenceTrait validation flow.
API conversion
internal/api/v1beta1connect/preferences.go
Transform maps Preference.ValueTitle and converts Trait.InputOptions into proto InputOptions (name/title pairs).
Build metadata
Makefile
Updated PROTON_COMMIT hash reference.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • rohilsurana
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically identifies the main change: adding InputHintOption for structured input options in preferences.
Description check ✅ Passed The description includes summary, changes, usage example, and dependencies. It covers the key structural additions and provides context, though technical details and test plan are minimal.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/preference-input-hints-object

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@core/preference/preference.go`:
- Around line 108-112: The TraitInputMultiselect branch incorrectly routes to
NewSelectValidatorFromOptions (used by TraitInputSelect/Combobox) causing
comma-separated values like "1,3" to fail SelectValidator.Validate; fix by
changing handling of TraitInputMultiselect in the switch so it does not use
SelectValidator: either return NewTextValidator() for TraitInputMultiselect
(simple fallback) or implement and return a new NewMultiselectValidator that
splits on commas, trims each token and validates each against the options
(mirroring SelectValidator logic for individual tokens). Update the branch that
currently checks len(t.InputOptions) > 0 (and the case label
TraitInputMultiselect) to use the chosen approach and ensure tests referencing
multiselect behavior pass.

In `@core/preference/validator.go`:
- Around line 59-70: NewSelectValidatorFromOptions currently appends raw
opt.Name values which can contain surrounding whitespace and cause mismatches;
update the function (NewSelectValidatorFromOptions) to trim whitespace (e.g.,
strings.TrimSpace) from each InputHintOption.Name before adding to allowedValues
and skip entries that are empty after trimming so the
SelectValidator.allowedValues list is normalized and matches NewSelectValidator
behavior.

Comment on lines 108 to 112
case TraitInputSelect, TraitInputCombobox, TraitInputMultiselect:
// Use InputOptions if available, otherwise fall back to InputHints
if len(t.InputOptions) > 0 {
return NewSelectValidatorFromOptions(t.InputOptions)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find how multiselect values are serialized and validated
rg -n -C3 '\.GetValidator\(' --type go

Repository: raystack/frontier

Length of output: 1063


🏁 Script executed:

# Search for TraitInputMultiselect usage and multiselect patterns
rg -n -C3 'TraitInputMultiselect|multiselect' --type go

Repository: raystack/frontier

Length of output: 3953


🏁 Script executed:

# Search for value splitting/processing patterns
rg -n -C3 'strings\.Split|json\.Unmarshal' --type go

Repository: raystack/frontier

Length of output: 50373


🏁 Script executed:

# Look at the SelectValidator implementation
rg -n -C10 'type SelectValidator|func.*SelectValidator' --type go

Repository: raystack/frontier

Length of output: 4323


🏁 Script executed:

# Check the preference.go file around the lines in question
cat -n core/preference/preference.go | head -130 | tail -40

Repository: raystack/frontier

Length of output: 1495


Multiselect is incorrectly routed through SelectValidator and will reject comma-separated values.

The code at lines 108–113 treats TraitInputMultiselect the same as TraitInputSelect and TraitInputCombobox, routing all three to SelectValidator. However, SelectValidator.Validate() performs exact-match validation against individual options using slices.Contains(). When a multiselect preference value like "1,3" is passed directly to this validator against options ["1", "2", "3"], the validation fails because "1,3" is not an exact match.

The test at line 102 of validator_test.go confirms this issue—its name explicitly states "multiselect falls back to text" and expects the comma-separated value "1,3" to validate as true against hints "1,2,3". Under the current SelectValidator implementation, this test would fail.

To fix this, either:

  1. Revert TraitInputMultiselect to use NewTextValidator() (fall back to text validation), or
  2. Create a dedicated multiselect validator that splits comma-separated values, trims each, and validates each one against the allowed options.
🤖 Prompt for AI Agents
In `@core/preference/preference.go` around lines 108 - 112, The
TraitInputMultiselect branch incorrectly routes to NewSelectValidatorFromOptions
(used by TraitInputSelect/Combobox) causing comma-separated values like "1,3" to
fail SelectValidator.Validate; fix by changing handling of TraitInputMultiselect
in the switch so it does not use SelectValidator: either return
NewTextValidator() for TraitInputMultiselect (simple fallback) or implement and
return a new NewMultiselectValidator that splits on commas, trims each token and
validates each against the options (mirroring SelectValidator logic for
individual tokens). Update the branch that currently checks len(t.InputOptions)
> 0 (and the case label TraitInputMultiselect) to use the chosen approach and
ensure tests referencing multiselect behavior pass.

Comment on lines +59 to +70
// NewSelectValidatorFromOptions creates a SelectValidator from InputHintOptions
// It extracts the Name field from each option as the allowed value
func NewSelectValidatorFromOptions(options []InputHintOption) *SelectValidator {
var allowed []string
for _, opt := range options {
if opt.Name != "" {
allowed = append(allowed, opt.Name)
}
}
return &SelectValidator{
allowedValues: allowed,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Trim option names to avoid mismatches.

NewSelectValidator trims whitespace but NewSelectValidatorFromOptions doesn’t, so a config like " sq_km " would never validate against "sq_km". Consider normalizing names for consistency.

Proposed fix
func NewSelectValidatorFromOptions(options []InputHintOption) *SelectValidator {
	var allowed []string
	for _, opt := range options {
-		if opt.Name != "" {
-			allowed = append(allowed, opt.Name)
+		if trimmed := strings.TrimSpace(opt.Name); trimmed != "" {
+			allowed = append(allowed, trimmed)
		}
	}
	return &SelectValidator{
		allowedValues: allowed,
	}
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// NewSelectValidatorFromOptions creates a SelectValidator from InputHintOptions
// It extracts the Name field from each option as the allowed value
func NewSelectValidatorFromOptions(options []InputHintOption) *SelectValidator {
var allowed []string
for _, opt := range options {
if opt.Name != "" {
allowed = append(allowed, opt.Name)
}
}
return &SelectValidator{
allowedValues: allowed,
}
// NewSelectValidatorFromOptions creates a SelectValidator from InputHintOptions
// It extracts the Name field from each option as the allowed value
func NewSelectValidatorFromOptions(options []InputHintOption) *SelectValidator {
var allowed []string
for _, opt := range options {
if trimmed := strings.TrimSpace(opt.Name); trimmed != "" {
allowed = append(allowed, trimmed)
}
}
return &SelectValidator{
allowedValues: allowed,
}
}
🤖 Prompt for AI Agents
In `@core/preference/validator.go` around lines 59 - 70,
NewSelectValidatorFromOptions currently appends raw opt.Name values which can
contain surrounding whitespace and cause mismatches; update the function
(NewSelectValidatorFromOptions) to trim whitespace (e.g., strings.TrimSpace)
from each InputHintOption.Name before adding to allowedValues and skip entries
that are empty after trimming so the SelectValidator.allowedValues list is
normalized and matches NewSelectValidator behavior.

- Add ValueTitle field to Preference struct
- Add GetValueTitle method to Trait for looking up title from InputOptions
- Populate ValueTitle in LoadUserPreferences from trait's InputOptions
- Only applies to select/combobox/multiselect input types

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@core/preference/preference.go`:
- Around line 132-140: The GetValueTitle method on Trait currently only matches
opt.Name exactly so comma-separated multiselect inputs like "opt1,opt2" return
empty; update Trait.GetValueTitle to detect if value contains commas, split by
"," (use strings.Split and strings.TrimSpace), look up each token against
t.InputOptions matching opt.Name to collect opt.Title values, then return the
joined titles (e.g., strings.Join with ", " or similar); ensure you add import
"strings" if not present and preserve existing exact-match behavior when value
has no commas.

Comment on lines +132 to +140
// GetValueTitle returns the human-readable title for a value from InputOptions
func (t Trait) GetValueTitle(value string) string {
for _, opt := range t.InputOptions {
if opt.Name == value {
return opt.Title
}
}
return ""
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

GetValueTitle won't resolve titles for multiselect values.

This method performs exact matching against opt.Name, so comma-separated multiselect values like "opt1,opt2" will always return "". This is related to the validation issue flagged earlier.

If multiselect support is intended, consider splitting the value and returning joined titles:

💡 Possible approach for multiselect title resolution
 // GetValueTitle returns the human-readable title for a value from InputOptions
 func (t Trait) GetValueTitle(value string) string {
+	// Handle comma-separated multiselect values
+	if strings.Contains(value, ",") {
+		var titles []string
+		for _, v := range strings.Split(value, ",") {
+			v = strings.TrimSpace(v)
+			for _, opt := range t.InputOptions {
+				if opt.Name == v {
+					titles = append(titles, opt.Title)
+					break
+				}
+			}
+		}
+		return strings.Join(titles, ", ")
+	}
 	for _, opt := range t.InputOptions {
 		if opt.Name == value {
 			return opt.Title
 		}
 	}
 	return ""
 }

Note: This requires import "strings" at the top of the file.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// GetValueTitle returns the human-readable title for a value from InputOptions
func (t Trait) GetValueTitle(value string) string {
for _, opt := range t.InputOptions {
if opt.Name == value {
return opt.Title
}
}
return ""
}
// GetValueTitle returns the human-readable title for a value from InputOptions
func (t Trait) GetValueTitle(value string) string {
// Handle comma-separated multiselect values
if strings.Contains(value, ",") {
var titles []string
for _, v := range strings.Split(value, ",") {
v = strings.TrimSpace(v)
for _, opt := range t.InputOptions {
if opt.Name == v {
titles = append(titles, opt.Title)
break
}
}
}
return strings.Join(titles, ", ")
}
for _, opt := range t.InputOptions {
if opt.Name == value {
return opt.Title
}
}
return ""
}
🤖 Prompt for AI Agents
In `@core/preference/preference.go` around lines 132 - 140, The GetValueTitle
method on Trait currently only matches opt.Name exactly so comma-separated
multiselect inputs like "opt1,opt2" return empty; update Trait.GetValueTitle to
detect if value contains commas, split by "," (use strings.Split and
strings.TrimSpace), look up each token against t.InputOptions matching opt.Name
to collect opt.Title values, then return the joined titles (e.g., strings.Join
with ", " or similar); ensure you add import "strings" if not present and
preserve existing exact-match behavior when value has no commas.

- Update PROTON_COMMIT to include InputHintOption and value_title changes
- Regenerate proto stubs
- Fix multiselect to use text validator (not select validator)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coveralls
Copy link

coveralls commented Feb 11, 2026

Pull Request Test Coverage Report for Build 21899742500

Details

  • 12 of 37 (32.43%) changed or added relevant lines in 4 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.004%) to 38.236%

Changes Missing Coverage Covered Lines Changed/Added Lines %
core/preference/preference.go 5 10 50.0%
internal/api/v1beta1connect/preferences.go 4 9 44.44%
core/preference/service.go 3 9 33.33%
core/preference/validator.go 0 9 0.0%
Totals Coverage Status
Change from base Build 21744973149: -0.004%
Covered Lines: 16119
Relevant Lines: 42157

💛 - Coveralls

- Add ValueTitle to Preference proto response for human-readable display
- Add InputOptions to PreferenceTrait proto response for select/combobox

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The Create method now populates ValueTitle from the matched trait's
InputOptions before returning the created preference.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/preference/service.go (1)

136-151: ⚠️ Potential issue | 🟡 Minor

ValueTitle is inconsistently exposed across API implementations.

While Create and LoadUserPreferences correctly populate ValueTitle, the service methods Get and List do not enrich the response. More critically, the two API implementations handle this differently:

  • internal/api/v1beta1connect/preferences.go: includes ValueTitle in the transformed response
  • internal/api/v1beta1/preferences.go: omits ValueTitle from the response entirely

This creates inconsistent data shapes depending on which API endpoint (Connect vs REST) clients use. Align the implementations by either:

  1. Populating ValueTitle in Get and List service methods (consistent with Create)
  2. Or explicitly document this field only applies to Create responses
  3. Or update v1beta1 to include ValueTitle like v1beta1connect does

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants