Process explicit user feedback for a previous request.
(self, request_id: str, signal: FeedbackSignal)
| 122 | self._save_buffer() |
| 123 | |
| 124 | def submit(self, request_id: str, signal: FeedbackSignal) -> FeedbackResult: |
| 125 | """Process explicit user feedback for a previous request.""" |
| 126 | ctx = self._buffer.pop(request_id, None) |
| 127 | if ctx is not None: |
| 128 | self._save_buffer() |
| 129 | |
| 130 | if ctx is None: |
| 131 | return FeedbackResult( |
| 132 | ok=False, action="expired", |
| 133 | reason="request_id not found or expired", |
| 134 | ) |
| 135 | |
| 136 | target = _adjust_tier(ctx.tier, signal) |
| 137 | if self._model_experience is not None and ctx.model: |
| 138 | self._model_experience.record_feedback( |
| 139 | ctx.model, |
| 140 | ctx.mode, |
| 141 | ctx.tier, |
| 142 | signal, |
| 143 | ) |
| 144 | |
| 145 | if signal == "ok": |
| 146 | self._do_update(ctx.features, ctx.tier) |
| 147 | return FeedbackResult( |
| 148 | ok=True, action="reinforced", |
| 149 | from_tier=ctx.tier, to_tier=ctx.tier, |
| 150 | ) |
| 151 | |
| 152 | if target == ctx.tier: |
| 153 | return FeedbackResult( |
| 154 | ok=True, action="no_change", |
| 155 | from_tier=ctx.tier, to_tier=ctx.tier, |
| 156 | reason="already at tier boundary", |
| 157 | ) |
| 158 | |
| 159 | if not self._rate_ok(): |
| 160 | return FeedbackResult( |
| 161 | ok=False, action="rate_limited", |
| 162 | reason=f"max {self._max_hourly} updates/hour", |
| 163 | ) |
| 164 | |
| 165 | self._do_update(ctx.features, target) |
| 166 | return FeedbackResult( |
| 167 | ok=True, action="updated", |
| 168 | from_tier=ctx.tier, to_tier=target, |
| 169 | ) |
| 170 | |
| 171 | def has_pending(self, request_id: str) -> bool: |
| 172 | """Check if feedback can still be submitted for a request.""" |