Skip to content

Moreh features on v1.5.0 - #4

Merged
hyeongyun0916 merged 10 commits into
moreh-v1.5.xfrom
merge-150
Apr 29, 2026
Merged

hyeongyun0916 merged 10 commits into
moreh-v1.5.xfrom
merge-150

Conversation

@hyeongyun0916

@hyeongyun0916 hyeongyun0916 commented Apr 27, 2026 •

Copy link
Copy Markdown

merge-150 commits (top of df9f890, oldest → newest)

# merge-150 SHA Subject Origin How it differs
1 7d36f1c feat(metrics): ITL/TTFT/TPOT Metrics and Responses API streaming hie#37 → #3 commit dfb7cba Reduced — metrics + predictedlatency hook only — superseded by row 9 (see review fix below)
2 ab10828 MAF-19412: fix(test): add SSE integration test newline... hie#39 → #3 commit 2ada5c6 Kept (excluding harness.go)
3 0c18711 MAF-19466: fix(test): add output_tokens metric assertion hie#40 → #3 commit a8453fd Kept as-is
4 1f7cfa6 MAF-19378: feat(saturation): add RunningRequestsDetector... hie#47 → #3 commit 7cfa97b Restructured — on top of pluggable SD
5 7fdf7b8 feat(epp): implement per-endpoint health check for scheduling #3 commits b35264e + d24a2d9 + b1ecd43 + febaa7c Squash — restructured on datalayer Runtime; unhealthy guard absorbed by upstream race fix; streamline refactor mostly subsumed by upstream
6 304f5ae feat(epp): preserve ResponsesRequest.Store field hie#41 → #3 commit 1d4a243 Mostly removed — only Store field preserved
7 af15049 feat(scheduling): add AudioURL field to ContentBlock #3 commit a33445f Kept as-is
8 8ce108b Revert "feat(metrics): ITL/TTFT/TPOT Metrics and Responses API streaming (hie#37)" revert of row 1 Reverts row 1; the metrics from hie#37 are re-introduced by row 9
9 df9607e feat(metrics): record TTFT/ITL/TPOT independently of predictedlatency re-port of hie#37 Addresses PR #4 review r3150283882: TTFT/ITL/TPOT now recorded directly in HandleResponseBody so they work without the predictedlatency plugin. Adds request_itl_seconds Histogram (only the gauge existed in row 1).
10 a444834 fix(test): drop unknown endpointPickerRef.namespace from e2e manifest (test infra fix) Removes spec.endpointPickerRef.namespace from test/testdata/inferencepool-e2e.yaml — strict CRD decoding rejects it and was preventing make test-e2e's BeforeSuite from creating the InferencePool

Skipped commits

Source Subject Reason
#3 commit e18a152 fix(streaming): remove premature ResponseComplete from [DONE] detection endOfStream resolves it naturally upstream

Outcome distribution

Outcome Count Notes
Kept 4 AudioURL, MAF-19412 (hie#39), MAF-19466 (hie#40), health tracking (within squash)
Restructured 2 RunningRequestsDetector (pluggable SD), per-endpoint health (datalayer Runtime)
Reduced / Partial 2 ITL/TTFT/TPOT (predictedlatency hook only) — later superseded by row 9, streamline refactor (within squash)
Naturally absorbed 1 unhealthy guard (upstream race fix)
Mostly removed 1 Responses store hie#41 (only Store field preserved)
SKIP 1 streaming fix (replaced by endOfStream)
Review-fix (post-port) 3 revert (row 8) of row 1, re-port to handlers + add ITL histogram (row 9), e2e manifest fix (row 10)

11 source commits → 10 merge-150 commits (7 ports + 1 revert + 2 review fixes).

…ernetes-sigs#37)

Adapted for v1.5 (upstream df9f890):
- Keep ITL/TTFT/TPOT Histogram + Gauge definitions (metrics.go).
- Move per-token ITL measurement into the predictedlatency plugin's
  per-token hook (processTokenForLatencyPrediction); RecordRequestITL
  is called from latencypredictor_helper.go instead of handlers/server.go
  because upstream's Pluggable Parser Framework (00edcef) replaced
  the SSE parsing that used to live in the handler.
- Move per-request average ITL gauge flush into the predictedlatency
  plugin's EndOfStream path (requestcontrol_hooks.go).
- TTFT/TPOT base metrics are recorded by upstream's handler path, so
  no direct changes to handlers are needed here.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
…API test case (kubernetes-sigs#39)

Adapted for v1.5 (upstream df9f890):
- SSE newline fix applied to the existing "response streaming: SSE
  token counting" test case in hermetic_test.go (upstream kept this
  test inline — it was not moved to common_tests.go).
- Added new "response streaming: Responses API token counting" test
  case after the SSE test. Exercises the Responses API streaming path
  (event: response.output_text.delta / event: response.completed).
- harness.go 1-line format-string fix from the original commit is
  intentionally excluded per maintainer direction.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
…sigs#40)

Add inference_objective_output_tokens histogram assertion to both
streaming test cases in hermetic_test.go:
- "response streaming: SSE token counting": sum=10 (Chat Completions).
- "response streaming: Responses API token counting": sum=20
  (Responses API output_tokens=20).

Mirrors the assertion already present in grpc_test.go for the gRPC
streaming path. No upstream-adaptation changes needed.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
…able SD selection (kubernetes-sigs#47)

Adapted for v1.5 (upstream df9f890):
- Upstream 5bdd01d promoted SaturationDetector to a pluggable
  extension point (fwkflowcontrol.SaturationDetector interface).
- RunningRequestsDetector moved from
  pkg/epp/saturationdetector/framework/plugins/runningrequestsdetector/
  to pkg/epp/framework/plugins/flowcontrol/saturationdetector/runningrequests/
  to follow the new plugin convention.
- Rewrote as fwkplugin.Plugin implementing
  Saturation(ctx, []datalayer.Endpoint) float64 (the new interface).
- Registered the plugin with RunningRequestsDetectorType
  "running-requests-detector" via fwkplugin.Register in runner.go,
  alongside utilization and concurrency detectors.
- The original config schema (SaturationDetector.Type switch),
  configloader buildSaturationDetectorType/buildRunningRequestsDetectorConfig
  functions, and runner switch block are not needed — upstream's
  registry-based plugin loading via pluginRef handles all detectors
  uniformly.
- To select this detector, set spec.parameters in the plugin config
  (maxConcurrencyPerPod, cacheTTL) and reference by pluginRef.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
Squashed for v1.5 (upstream df9f890) — combines PR #3 commits
b35264e + d24a2d9 + b1ecd43 + febaa7c into a single commit because
upstream's datalayer plugins-runtime separation (dc2f1fe) and race fix
(a1f0b01) reshape the files these four commits touched, making a clean
per-commit split impractical.

What this commit delivers:

- PoolInfo.EndpointSetHealthy(ep, healthy bool) interface added
  (pkg/epp/datalayer/factory.go) so the collector can report
  per-endpoint health. Datastore implements it to flip a pod in/out
  of the PodList filter.

- Collector rewrite:
  - Added poolInfo field + NewCollector(poolInfo) signature.
  - Aggregates poll errors with errors.Join across sources and calls
    EndpointSetHealthy(endpoint, pollErrs == nil) after each tick.
  - Keeps upstream's lastPollErrors/lastExtractErrors change-only
    logging + extractor dispatch.

- Runtime.NewEndpoint forwards poolInfo to NewCollector
  (pkg/epp/datalayer/runtime.go).

- Datastore adds unhealthyEndpoints sync.Map to track endpoints marked
  unhealthy. PodList filters them out; Clear/PodDelete/podResyncAll
  remove them alongside the pods map. Recovery flips them back
  automatically when the next successful poll arrives.

- Backend metrics refresh loop (legacy path) reports health via
  EndpointSetHealthy when FetchMetrics succeeds/fails.

- PodMetricsFactory tracks active endpoints by NamespacedName via a
  sync.Map and returns nil from NewEndpoint when a collector is
  already running for that endpoint — prevents a pod-update event
  from re-spawning a goroutine for an endpoint whose existing
  collector is still handling recovery. This subsumes d24a2d9's
  "prevent re-add on pod update" guard.

- FakeDataSource Poll-error propagation migrated into
  source/mocks/data_source_mock.go: when SetErrors is set for an
  endpoint, Poll returns that error so the health-check path
  triggers.

- All downstream test stubs (FakeOddMetricsDataStore,
  FakeRefresherDataStore, datalayer/logger_test stubs) implement the
  new EndpointSetHealthy no-op method.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
…ubernetes-sigs#41)

Adapted for v1.5 (upstream df9f890):
- PR kubernetes-sigs#41 (MAF-19473) added RawBody/ResponseBodyJSON/CurrentStreamingBody/
  PrepareDataPlugin 404-error-propagation + Director Responses dispatch +
  plugin_executor hook. These are all superseded by upstream's Pluggable
  Parser Framework (00edcef via LLMRequestBody.Body / ParsedBody) and
  are therefore intentionally dropped in this merge.
- However, upstream's ResponsesRequest does NOT include a Store field.
  The downstream scheduler's ResponsesStorePlugin reads body.Responses.Store
  to decide whether to persist the response. Preserving just this one
  field as a Moreh-local diff on the upstream type keeps the plugin
  working without further changes downstream.
- Consider proposing this field to upstream in a follow-up so the next
  merge has one less local delta.

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
Add AudioURL (audio_url) multimodal content block type alongside existing
InputAudio (input_audio). vLLM 0.18+ strictly validates audio_url via pydantic
ChatCompletionContentPartAudioParam, rejecting requests that carry an
audio_url type without the matching field.
Comment thread pkg/epp/metrics/metrics.go Outdated
typeTTFTSLOViolation = "ttft_slo_violation"
typeTTFTSLOThreshold = "ttft_slo_threshold" // Moreh MAF-19466

typeITL = "itl" // Moreh 5701fa97

@bongwoobak bongwoobak Apr 27, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(Leaving this here as there’s no other place to put it)

It seems the part for collecting ITL when the predictedlatency plugin is disabled in hie#37 (per-token measurement in HandleResponseBodyModelStreaming of pkg/epp/handlers/response.go + EndOfStream aggregation in pkg/epp/handlers/server.go) is missing.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>
…tdata/inferencepool-e2e.yaml that strict CRD decoding rejects

Signed-off-by: HyunKyun Moon <mhg5303@gmail.com>

@nulledge nulledge left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I checked 3 changes:

ImageURL ImageBlock `json:"image_url"`
InputAudio AudioBlock `json:"input_audio"`
AudioURL AudioURLBlock `json:"audio_url"`
VideoURL VideoBlock `json:"video_url"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FYI) vLLM v0.17.* requires the audio_url field when contentType=audio_url.

Without this change, the multi-modal test was failed.

Also, llm-d-kv-cache should support audio_url [Link].

@bongwoobak bongwoobak left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@hyeongyun0916
hyeongyun0916 merged commit 823407c into moreh-v1.5.x Apr 29, 2026
6 checks passed
@hyeongyun0916
hyeongyun0916 deleted the merge-150 branch April 29, 2026 07:14
@hyeongyun0916
hyeongyun0916 restored the merge-150 branch April 30, 2026 06:00
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.

3 participants