Skip to content

feat: add advanced model route conditions, close #1670#1717

Merged
looplj merged 1 commit into
unstablefrom
dev-tmp
May 25, 2026
Merged

feat: add advanced model route conditions, close #1670#1717
looplj merged 1 commit into
unstablefrom
dev-tmp

Conversation

@looplj

@looplj looplj commented May 25, 2026

Copy link
Copy Markdown
Owner

@greptile-apps

greptile-apps Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends the model route condition system with two new filter fields — request_format (equality match against the inbound API format) and daily_time (time-window match with overnight wrap-around support) — and adds the necessary frontend UI, backend validation, and expression-engine wiring.

  • Backend: xtime.ParseDailyTimeRange / DailyTimeWithin centralize time-range parsing (resolving the previously noted duplication). conditionToExpr emits a dailyTimeWithin(now, …) call for daily_time conditions, and now / request_format are injected into the evaluation context in filterResolvedCandidatesForRequest.
  • Frontend: the FilterBuilder gains an options prop to render a dropdown for fixed-choice fields; request_format uses it, daily_time remains a free-text input. Client-side Zod validation for daily_time correctly rejects empty and equal-endpoint ranges, but the parallel check for request_format is missing an empty-string guard, allowing the form to submit when no format has been selected.
  • Tests: both the xtime helpers and the orchestrator condition evaluator gain comprehensive unit tests covering normal, overnight, edge-case, and error scenarios.

Confidence Score: 4/5

Safe to merge after fixing the frontend validation gap for empty request_format values.

The backend logic is solid — time-range parsing, overnight wrap-around, operator validation, and expression generation are all correct and well-tested. The one defect is on the frontend: when a user adds a request_format condition but never picks a format, the value is an empty string that passes Zod validation and reaches the API, which returns a server-side error instead of an inline field error. Every other new condition type handles the empty state client-side; request_format is missing that guard.

frontend/src/features/models/components/models-association-dialog.tsx — the request_format condition validation block needs an empty-string check alongside the typeof guard.

Important Files Changed

Filename Overview
frontend/src/components/filter-builder.tsx Adds options field to FilterBuilderField type and a new Select branch that renders a dropdown when field.options is provided; logic is clean and consistent with existing boolean/text branches.
frontend/src/features/models/components/models-association-dialog.tsx Adds request_format and daily_time filter fields; the daily_time client-side validation is thorough but request_format is missing an empty-string guard, allowing a form submit with no format selected that will fail server-side.
internal/pkg/xtime/time.go Adds ParseDailyTimeRange and DailyTimeWithin helpers; handles normal, overnight (wrap-around), and equal-endpoint cases correctly.
internal/objects/condition.go Registers dailyTimeWithin as a custom expr function and adds daily_time branch to conditionToExpr; function defensively handles wrong param count and non-time.Time arguments by returning false rather than erroring.
internal/server/biz/model.go Adds validateStringEqualityLeaf and validateDailyTimeLeaf to the condition validation switch; delegates time-range parsing to the shared xtime.ParseDailyTimeRange, eliminating the previously duplicated logic.
internal/server/orchestrator/candidates_condition.go Captures requestFormat and now once before the candidate loop and passes them to matchesAssociationWhen; now is a consistent snapshot for the entire request evaluation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant APIHandler
    participant Orchestrator
    participant ConditionEval as objects.Evaluate
    participant XTime as xtime.DailyTimeWithin

    Client->>APIHandler: POST /v1/... (sets req.APIFormat)
    APIHandler->>Orchestrator: filterResolvedCandidatesForRequest(req)
    Orchestrator->>Orchestrator: "requestFormat = req.APIFormat"
    Orchestrator->>Orchestrator: "now = time.Now()"
    loop For each association candidate
        Orchestrator->>ConditionEval: "Evaluate(condition, {prompt_tokens, stream, request_format, now})"
        alt daily_time condition
            ConditionEval->>XTime: DailyTimeWithin(now, HH:mm-HH:mm)
            XTime-->>ConditionEval: bool
        else request_format condition
            ConditionEval->>ConditionEval: "request_format == value"
        end
        ConditionEval-->>Orchestrator: bool
    end
    Orchestrator-->>APIHandler: filtered candidates
Loading

Reviews (2): Last reviewed commit: "feat: add advanced model route condition..." | Re-trigger Greptile

Comment thread internal/server/orchestrator/candidates_condition.go
Comment thread internal/server/biz/model.go Outdated

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

Comment on lines 138 to +144
return (value?.groups || []).some((group) => hasConditionNodeData(group));
}

function hasDailyTimeConditionNode(condition?: FilterBuilderCondition): boolean {
if (!condition) {
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Missing empty-string guard for request_format value

When a user selects request_format as the condition field the value is initialised to '' (see filter-builder.tsx line 346). The validation block here only tests typeof condition.value !== 'string', which is false for an empty string, so the user can submit without ever choosing a format and the form will pass client-side Zod validation. The backend's validateStringEqualityLeaf rejects the empty string with an error, so the user sees a confusing server-side error instead of an inline UI message.

daily_time already handles this correctly because a second check tests the regex (which rejects ''). The request_format check needs an analogous non-empty guard.

@looplj looplj merged commit bcd0b64 into unstable May 25, 2026
4 checks passed
junjiangao pushed a commit to junjiangao/axonhub that referenced this pull request May 27, 2026
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.

1 participant