Conversation
- Fix statusText bug: was `HTTP/1.1 200 200`, now `HTTP/1.1 200 OK` (use STATUS_CODES from node:http instead of String(statusCode)) - Fix Gemini request body handling: skip JSON.stringify for GET/HEAD requests which should not have a body
Allow Request Filters to be applied globally, to specific providers, or to provider groups.
## Key Changes
### Database Schema
- Add `bindingType` field ('global' | 'providers' | 'groups')
- Add `providerIds` field (array of provider IDs)
- Add `groupTags` field (array of group tags)
- Migration: 0041_sticky_jackal.sql
### Backend Logic
- Split filter engine into global and provider-specific filters
- `applyGlobal()`: runs BEFORE provider selection
- `applyForProvider()`: runs AFTER provider selection
- Provider matching: checks provider IDs or group tags
### Guard Pipeline
- Add new `providerRequestFilter` guard step
- CHAT_PIPELINE order: [..., provider, providerRequestFilter, messageContext]
- COUNT_TOKENS_PIPELINE includes provider filters
### UI Components
- New: `ProviderMultiSelect` - multi-select for providers
- New: `GroupMultiSelect` - multi-select for group tags
- Updated: `FilterDialog` - binding type selector moved after Name field
- Updated: `FilterTable` - compact layout with icon-only display
- Binding display: Global (icon only), Providers (icon + count), Groups (icon + count)
### Localization
- Add translations for 5 languages (en, ru, ja, zh-CN, zh-TW)
- Column name changed from "Apply To" to "Apply"
### Bug Fixes
- Fix binding type change validation (use explicit undefined check instead of ??)
- Prevent stale binding data when switching types
### Other Improvements
- Compact last 4 columns in filter table (Priority, Apply, Status, Actions)
- Improved UX: binding configuration at top of dialog
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add truncate to name, target, and replacement columns to keep table rows single-line - Add tooltips on Apply column showing provider names or group tags on hover - Fetch provider list to display names instead of IDs in tooltips - Optimize provider lookup with useMemo Map (O(1) access) - Add i18n translations for tooltip labels (en, ja, ru, zh-CN, zh-TW) - Optimize request filter engine with caching and early exits 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Set max-w-2xl width for consistency with error rules dialog - Add max-h-80vh height limit to prevent overflow - Restructure layout with fixed header and footer - Make only content area scrollable when form has many fields - Ensures Cancel/Save buttons and close button always accessible 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add 28 unit tests for RequestFilterEngine binding functionality - Cover global, provider-specific, and group-specific filters - Test combined filters and edge cases - Fix setFiltersForTest to sort by priority (matching reload behavior) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Iterate over provider tags (typically 1-3) instead of filter group tags for faster set intersection check. Suggested by: @gemini-code-assist 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…r fields (#456) - Add InlineEditPopover component with Popover + Input + save/cancel buttons - Integrate inline editing in ProviderRichListItem for admin users - Add i18n strings for 5 locales (en/ja/ru/zh-CN/zh-TW) - Allow weight minimum value to be 0 (PROVIDER_LIMITS.WEIGHT.MIN) - Add keyboard focus styles and upper bound validation - Add unit tests for schema validation rules
Weight=0 previously meant "skip this provider in weighted selection", which was confusing. Now enforce 1-100 range; disable the provider via is_enabled flag instead. - Update PROVIDER_LIMITS.WEIGHT.MIN to 1 - Add Chinese error messages to Zod schemas - Update all 5 locale error messages - Adjust unit tests accordingly
- Consolidate handleSavePriority, handleSaveWeight, handleSaveCostMultiplier into a single createSaveHandler factory function - Fix incorrect error message key in catch block (deleteError → unknownError)
…ting Fix #456: Add inline editing for provider priority, weight and cost multiplier
feat: add provider/group binding for request filters
fix: correct HTTP statusText and Gemini GET/HEAD handling
Summary of ChangesHello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a major upgrade to the request filtering capabilities, moving beyond global-only filters to support granular control at the provider and provider group levels. This change empowers administrators with more precise tools for managing request flows and provider interactions. Alongside this core feature, the PR introduces convenient inline editing for provider settings and includes several performance enhancements to the request filtering engine, ensuring efficient operation of the new functionalities. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
🧪 测试结果
总体结果: ✅ 所有测试通过 |
There was a problem hiding this comment.
Code Review
This pull request introduces a major feature allowing request filters to be bound to specific providers or provider groups, enhancing the flexibility of request modification. The implementation is comprehensive, touching the database schema, backend engine, server actions, and frontend UI. Key highlights include a significant performance-oriented refactoring of the request-filter-engine, the addition of new UI components for provider/group selection, and an inline editing feature for provider settings. The introduction of extensive unit tests for the new logic is also a great addition.
I've identified a critical bug in the request filter engine that could cause crashes and a medium-severity issue related to handling HTTP status text. My review includes suggestions to fix these issues. Overall, this is a high-quality contribution with well-thought-out architecture and implementation.
| let providerTagsSet: Set<string> | null = null; | ||
| if (this.hasGroupBasedFilters) { | ||
| const providerGroupTag = session.provider.groupTag; | ||
| providerTagsSet = new Set(providerGroupTag?.split(",").map((t) => t.trim()) ?? []); |
There was a problem hiding this comment.
There's a potential TypeError here. If providerGroupTag is null or undefined, providerGroupTag?.split(",") will evaluate to undefined. Calling .map() on undefined will then throw an exception, crashing the request processing for any provider that doesn't have a group tag when group-based filters are active.
The nullish coalescing operator ?? should be used to provide a default empty value before calling .split() to ensure the code is robust against null or undefined values.
| providerTagsSet = new Set(providerGroupTag?.split(",").map((t) => t.trim()) ?? []); | |
| providerTagsSet = new Set((providerGroupTag ?? "").split(",").map((t) => t.trim())); |
src/app/v1/_lib/proxy/forwarder.ts
Outdated
| return new Response(bodyStream, { | ||
| status: undiciRes.statusCode, | ||
| statusText: String(undiciRes.statusCode), | ||
| statusText: STATUS_CODES[undiciRes.statusCode] ?? "OK", |
There was a problem hiding this comment.
Using "OK" as a fallback for statusText can be misleading for non-2xx status codes. If undiciRes.statusCode is a non-standard code not present in STATUS_CODES, the status text will incorrectly be "OK". For example, a response with status: 499 would have statusText: "OK".
It's safer to provide undefined or an empty string and let the Response constructor or the client use the default status text for the given status code. By removing the fallback, undefined will be passed if the code is not found, which is handled correctly by the Response constructor.
| statusText: STATUS_CODES[undiciRes.statusCode] ?? "OK", | |
| statusText: STATUS_CODES[undiciRes.statusCode], |
There was a problem hiding this comment.
Code Review Summary
This is a well-structured release (v0.3.39) implementing request filter provider/group binding, provider inline editing, and important bug fixes. The code quality is high with comprehensive testing and proper error handling throughout.
PR Size: XL
- Lines changed: 4128 additions, 83 deletions
- Files changed: 26
Note: For future XL PRs, consider splitting into smaller focused PRs to improve reviewability and reduce merge risk.
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Review Summary
No significant issues identified. This PR demonstrates:
Strengths:
- Excellent test coverage: 28 comprehensive unit tests covering all binding scenarios (645+ lines)
- Proper error handling: All catch blocks log errors and implement fail-open behavior appropriately
- Performance optimizations: Pre-compiled regex caching, Set-based O(1) provider/group lookups, early exit optimizations
- Memory leak fix: Event listener cleanup added in
request-filter-engine.ts - Type safety: Proper TypeScript types throughout with discriminated unions
- Security: ReDoS validation for regex patterns in both create and update operations
- Good architecture: Clean separation of
applyGlobal()andapplyForProvider()methods
Notable Changes:
RequestFilterEngine: Two-phase filtering with performance optimizationsProxyProviderRequestFilter: New guard step for provider-specific filteringGuardPipeline: Provider filter step added after provider selectionProxyForwarder: HTTP statusText fix usingSTATUS_CODESmap, Gemini GET/HEAD fix
Minor Observations (Informational):
- The
destroy()method onRequestFilterEngineis defined but no explicit cleanup call was found in lifecycle hooks (this is acceptable as Node.js process cleanup handles this) - Some Russian comments mixed with Chinese comments in
request-filter-engine.ts(cosmetic, doesn't affect functionality) - Weight minimum changed from 0 to 1 - this is a breaking change but well-documented in PR description
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean (ReDoS protection present)
- Error handling - Clean (fail-open with proper logging)
- Type safety - Clean
- Documentation accuracy - Clean
- Test coverage - Excellent (28 new tests)
- Code clarity - Good
Automated review by Claude AI
| const [filters, providers] = await Promise.all([listRequestFilters(), findAllProviders()]); | ||
|
|
||
| return <FilterTable filters={filters} />; | ||
| return <FilterTable filters={filters} providers={providers} />; |
There was a problem hiding this comment.
[Critical] [SECURITY-VULNERABILITY] Provider secret keys can be leaked to the client via providers prop
File: src/app/[locale]/settings/request-filters/page.tsx:30
This passes providers into a "use client" component:
return <FilterTable filters={filters} providers={providers} />;
findAllProviders() returns full Provider rows including key (see src/repository/provider.ts:185 selecting key: providers.key). Next.js will serialize the entire providers array into the client payload, exposing upstream API keys in the browser.
Suggested fix:
// src/app/[locale]/settings/request-filters/page.tsx
const [filters, providers] = await Promise.all([listRequestFilters(), findAllProviders()]);
const providerOptions = providers.map((p) => ({ id: p.id, name: p.name }));
return <FilterTable filters={filters} providers={providerOptions} />;And tighten the client component prop type to prevent regressions:
// src/app/[locale]/settings/request-filters/_components/filter-table.tsx
interface Props {
filters: RequestFilter[];
providers: Array<{ id: number; name: string }>;
}|
|
||
| interface Props { | ||
| filters: RequestFilter[]; | ||
| providers: Provider[]; |
There was a problem hiding this comment.
[Critical] [SECURITY-VULNERABILITY] Client prop type providers: Provider[] makes it easy to leak secrets
File: src/app/[locale]/settings/request-filters/_components/filter-table.tsx:23
This is a "use client" component, and Provider includes key: string (src/types/provider.ts:24). If a caller passes full Provider objects (as page.tsx does in this PR), Next.js will serialize the secret key into the browser payload.
Suggested fix:
// src/app/[locale]/settings/request-filters/_components/filter-table.tsx
interface Props {
filters: RequestFilter[];
providers: Array<{ id: number; name: string }>;
}Then ensure callers pass only { id, name } objects.
| <CommandItem | ||
| key={provider.id} | ||
| value={`${provider.name} ${provider.id}`} | ||
| onSelect={() => toggleProvider(provider.id)} |
There was a problem hiding this comment.
[High] [LOGIC-BUG] Provider selection can double-toggle when clicking the checkbox
File: src/app/[locale]/settings/request-filters/_components/provider-multi-select.tsx:130
CommandItem toggles selection on onSelect, and the nested Checkbox toggles again on onCheckedChange:
onSelect={() => toggleProvider(provider.id)}onCheckedChange={() => toggleProvider(provider.id)}
Because the checkbox click bubbles to the CommandItem, both handlers can run, causing a double-toggle (often a no-op/flicker).
Suggested fix (keep row-click support, remove the duplicate handler):
<CommandItem onSelect={() => toggleProvider(provider.id)}>
<Checkbox checked={selectedProviderIds.includes(provider.id)} className="mr-2" />
{/* ... */}
</CommandItem>| <CommandItem | ||
| key={groupTag} | ||
| value={groupTag} | ||
| onSelect={() => toggleGroup(groupTag)} |
There was a problem hiding this comment.
[High] [LOGIC-BUG] Group selection can double-toggle when clicking the checkbox
File: src/app/[locale]/settings/request-filters/_components/group-multi-select.tsx:130
Same double-toggle pattern as ProviderMultiSelect: the item toggles on onSelect, and the nested Checkbox toggles again on onCheckedChange. A checkbox click can bubble and execute both handlers, resulting in a no-op/flicker.
Suggested fix (keep row-click support, remove the duplicate handler):
<CommandItem onSelect={() => toggleGroup(groupTag)}>
<Checkbox checked={selectedGroupTags.includes(groupTag)} className="mr-2" />
{/* ... */}
</CommandItem>
src/lib/request-filter-engine.ts
Outdated
| // Optimization #2: Pre-compile regex for text_replace | ||
| if (f.matchType === "regex" && f.action === "text_replace") { | ||
| try { | ||
| cached.compiledRegex = new RegExp(f.target, "g"); |
There was a problem hiding this comment.
[High] [SECURITY-VULNERABILITY] compiledRegex path bypasses the existing safeRegex (ReDoS) guard
File: src/lib/request-filter-engine.ts:176
There is an explicit ReDoS guard in the fallback regex path:
if (!safeRegex(target)) { ... return input; } (src/lib/request-filter-engine.ts:92-95)
But when compiledRegex is present, the engine does:
return input.replace(re, replacement); (src/lib/request-filter-engine.ts:84)
…and compiledRegex is populated at load time without any safeRegex check:
cached.compiledRegex = new RegExp(f.target, "g"); (src/lib/request-filter-engine.ts:176)
So an unsafe-but-valid regex pattern loaded from the DB could execute in the proxy hot path.
Suggested fix (validate once at load time, and mirror in setFiltersForTest):
if (f.matchType === "regex" && f.action === "text_replace") {
if (!safeRegex(f.target)) {
logger.warn("[RequestFilterEngine] Skip unsafe regex at load", {
filterId: f.id,
target: f.target,
});
} else {
cached.compiledRegex = new RegExp(f.target, "g");
}
}There was a problem hiding this comment.
Code Review Summary
This PR introduces provider/group-bound request filters and related UI/proxy pipeline changes. There is a critical security regression where full Provider objects (including secret key) are passed into a client component and will be serialized to the browser. The new multi-select components can also double-toggle on checkbox clicks, and the request-filter engine’s compiled-regex path bypasses the existing ReDoS guard.
PR Size: XL
- Lines changed: 4211
- Files changed: 26
- Split suggestion: Separate the Drizzle migration/meta snapshot changes from the request-filter engine/proxy pipeline changes, and split the admin UI/i18n updates into a dedicated PR to make review/rollback safer.
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 2 | 0 | 0 |
| Security | 1 | 1 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Critical Issues (Must Fix)
- (Confidence 100) Secret provider
keyis exposed to the browser by passing full providers into a client component:src/app/[locale]/settings/request-filters/page.tsx:30andsrc/app/[locale]/settings/request-filters/_components/filter-table.tsx:23.
High Priority Issues (Should Fix)
- (Confidence 90) Checkbox click can trigger a double-toggle (row
onSelect+ checkboxonCheckedChange) in provider selector:src/app/[locale]/settings/request-filters/_components/provider-multi-select.tsx:130. - (Confidence 90) Checkbox click can trigger a double-toggle (row
onSelect+ checkboxonCheckedChange) in group selector:src/app/[locale]/settings/request-filters/_components/group-multi-select.tsx:130. - (Confidence 88)
compiledRegexexecution bypasses the existingsafeRegexguard (ReDoS risk) when loading regex filters:src/lib/request-filter-engine.ts:176.
Review Coverage
- Logic and correctness
- Security (OWASP Top 10)
- Error handling
- Type safety
- Documentation accuracy
- Test coverage
- Code clarity
Automated review by Codex AI
There was a problem hiding this comment.
- PR
#487labeledsize/XL(4211 lines changed, 26 files). - Posted 5 inline review comments covering:
- Critical security leak: passing full
Providerobjects (incl. secretkey) into a client component (src/app/[locale]/settings/request-filters/page.tsx:30,src/app/[locale]/settings/request-filters/_components/filter-table.tsx:23) - High logic bugs: checkbox click can double-toggle in both multi-selects (
src/app/[locale]/settings/request-filters/_components/provider-multi-select.tsx:130,src/app/[locale]/settings/request-filters/_components/group-multi-select.tsx:130) - High security/perf risk:
compiledRegexpath bypasses the existingsafeRegexguard (src/lib/request-filter-engine.ts:176)
- Critical security leak: passing full
- Submitted the required review summary via
gh pr review --comment.
Address 4 bugs identified in code review (Codex AI):
1. CRITICAL: Prevent provider API keys leak to browser
- Only pass {id, name} to client component FilterTable
- Remove Provider type import, use inline type
- Files: page.tsx, filter-table.tsx
2. HIGH: Add ReDoS validation for pre-compiled regex
- Check safeRegex() before compiling in reload()
- Check safeRegex() in setFiltersForTest()
- Skip unsafe patterns with warning log
- File: request-filter-engine.ts
3. MEDIUM: Fix double-toggle in provider multi-select
- Remove duplicate onCheckedChange handler
- Keep only onSelect on CommandItem
- File: provider-multi-select.tsx
4. MEDIUM: Fix double-toggle in group multi-select
- Remove duplicate onCheckedChange handler
- Keep only onSelect on CommandItem
- File: group-multi-select.tsx
All 28 unit tests pass after fixes.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Add explicit error logging when regex compilation fails in test helper for consistency with reload() method and easier test debugging. Suggested by: @gemini-code-assist 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: address security and UX issues in request filters
🧪 测试结果
总体结果: ✅ 所有测试通过 |
重构 webhook 通知系统,支持飞书和微信两种平台。 - 引入 StructuredMessage 抽象层实现多平台渲染 - 添加飞书卡片消息渲染器 - 统一消息模板(熔断、成本、排行榜) - 支持指数退避重试 BREAKING CHANGE: WeChatBot API 已替换为 WebhookNotifier Signed-off-by: Kevin Cui <bh@bugs.cc>
Signed-off-by: Kevin Cui <bh@bugs.cc>
Signed-off-by: Kevin Cui <bh@bugs.cc>
🧪 测试结果
总体结果: ✅ 所有测试通过 |
feat(notification): add Feishu webhook support
🧪 测试结果
总体结果: ✅ 所有测试通过 |
…splay - Fix i18n key: checkInterval -> interval for cost alert settings - Add webhook type auto-detection based on URL hostname (WeCom/Feishu) - Display platform badge next to webhook URL inputs - Show warning for unrecognized webhook platforms - Add i18n translations for webhook type labels (5 locales) Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🧪 测试结果
总体结果: ✅ 所有测试通过 |
Summary
Release v0.3.39 merges feature branch
devintomain, bringing provider management enhancements, request filter improvements, and important bug fixes.Problem
This release addresses several user-requested improvements and bug fixes:
HTTP/1.1 200 200instead ofHTTP/1.1 200 OK)Solution
Provider Management Enhancements (#486)
Added inline editing capability for provider configuration fields:
canEditpermission checkis_enabled=falseRequest Filter Provider/Group Binding (#484)
Extended request filters with granular binding capabilities:
global(all requests),providers(specific provider IDs),groups(provider group tags)applyGlobal()runs before provider selection,applyForProvider()runs afterbinding_type,provider_ids,group_tagscolumns with indexed lookupsHTTP and Gemini Fixes (#481)
Fixed two separate bugs in the proxy forwarder:
String(statusCode)toSTATUS_CODES[statusCode]using Node.js's built-in mapChanges
Core Changes
src/drizzle/schema.ts,drizzle/0041_sticky_jackal.sqlsrc/lib/request-filter-engine.tssrc/app/v1/_lib/proxy/guard-pipeline.ts,provider-request-filter.ts,forwarder.ts,request-filter.tssrc/app/[locale]/settings/providers/_components/inline-edit-popover.tsx,provider-rich-list-item.tsxsrc/app/[locale]/settings/request-filters/_components/*src/actions/request-filters.tssrc/lib/validation/schemas.ts,schemas.test.tsSupporting Changes
messages/{en,ja,ru,zh-CN,zh-TW}/settings.jsonfor new UI stringssrc/repository/request-filters.tsadded binding query methodstests/unit/request-filter-binding.test.tswith 28 comprehensive testsBreaking Changes
is_enabled=falseinsteadbinding_type,provider_ids,group_tagsTesting
Automated Tests
Manual Testing
HTTP/1.1 200 OK)Related Issues/PRs
🤖 Generated with Claude Code
Greptile Summary
This release implements advanced request filter binding with three binding types: global (all providers), provider-specific, and group-based filters. The feature includes:
Major Changes:
binding_type,provider_ids, andgroup_tagscolumns torequest_filterstable with proper indexingProxyProviderRequestFilterguard component integrated into both CHAT and COUNT_TOKENS pipelinesUI Enhancements:
InlineEditPopovercomponent for inline editing of numeric provider fieldsPerformance & Quality:
Bug Fixes:
STATUS_CODESinstead of numeric string in forwarderConfidence Score: 5/5
apply()method maintained.Important Files Changed
Sequence Diagram
sequenceDiagram participant Client participant Pipeline as Guard Pipeline participant GlobalFilter as Request Filter (Global) participant ProviderSelector as Provider Selector participant ProviderFilter as Provider Request Filter participant Engine as Request Filter Engine participant Provider as Upstream Provider Client->>Pipeline: API Request Pipeline->>GlobalFilter: Apply Global Filters GlobalFilter->>Engine: applyGlobal(session) Note over Engine: Apply filters with bindingType='global'<br/>to headers and body Engine-->>GlobalFilter: Request Modified GlobalFilter-->>Pipeline: Continue Pipeline->>ProviderSelector: Select Provider Note over ProviderSelector: Choose provider based on<br/>routing logic, weights, etc. ProviderSelector-->>Pipeline: Provider Selected Pipeline->>ProviderFilter: Apply Provider-Specific Filters ProviderFilter->>Engine: applyForProvider(session) Note over Engine: Apply filters with bindingType='providers'<br/>matching session.provider.id<br/>OR bindingType='groups'<br/>matching session.provider.groupTag Engine-->>ProviderFilter: Request Modified ProviderFilter-->>Pipeline: Continue Pipeline->>Provider: Forward Request Provider-->>Pipeline: Response Pipeline-->>Client: Response