文件最后提交记录最后更新时间
fix(model): make provider credentials whitespace-tolerant + per-turn config refetch A stray space in a YAML quoted apiKey (apiKey: " sk-...") survived all the way to the wire as Authorization: Bearer sk-..., which most providers reject as invalid_token / 无效的令牌. Even after the user "fixed" it via the UI a copy-paste with leading/trailing whitespace would re-introduce the same footgun. Defence in depth: - resolveApiKey trims the literal value and any ${VAR}-resolved env value; whitespace-only is still rejected as missing_api_key. - parseProvider trims provider.url so a stray newline in a baseURL doesn't break URL construction either. - streamModel.buildHeaders trims apiKey one more time at the wire boundary as a defence against callers that bypass parseModelConfig. - ui/server sanitises provider.apiKey/url before writing to disk so the saved yaml stays diff-clean and watcher-friendly. Per-turn config refresh hook so an apiKey edit takes effect on the very next message even when the fs watcher misses an event (network mounts, debounce gaps, container snapshots): InProcessGateway gains an optional refreshConfigBeforeTurn hook awaited at the top of submitTurn; createLocalGateway wires it to configStore.reload, which is singleton-deduped and a no-op when the yaml hasn't changed. Tests cover whitespace tolerance (literal + env, openai + anthropic header paths), url trim, and the per-turn refresh ordering + error swallow. 116 model+gateway tests pass / 0 fail. Co-authored-by: Cursor <cursoragent@cursor.com> 18 天前
fix(model): make provider credentials whitespace-tolerant + per-turn config refetch A stray space in a YAML quoted apiKey (apiKey: " sk-...") survived all the way to the wire as Authorization: Bearer sk-..., which most providers reject as invalid_token / 无效的令牌. Even after the user "fixed" it via the UI a copy-paste with leading/trailing whitespace would re-introduce the same footgun. Defence in depth: - resolveApiKey trims the literal value and any ${VAR}-resolved env value; whitespace-only is still rejected as missing_api_key. - parseProvider trims provider.url so a stray newline in a baseURL doesn't break URL construction either. - streamModel.buildHeaders trims apiKey one more time at the wire boundary as a defence against callers that bypass parseModelConfig. - ui/server sanitises provider.apiKey/url before writing to disk so the saved yaml stays diff-clean and watcher-friendly. Per-turn config refresh hook so an apiKey edit takes effect on the very next message even when the fs watcher misses an event (network mounts, debounce gaps, container snapshots): InProcessGateway gains an optional refreshConfigBeforeTurn hook awaited at the top of submitTurn; createLocalGateway wires it to configStore.reload, which is singleton-deduped and a no-op when the yaml hasn't changed. Tests cover whitespace tolerance (literal + env, openai + anthropic header paths), url trim, and the per-turn refresh ordering + error swallow. 116 model+gateway tests pass / 0 fail. Co-authored-by: Cursor <cursoragent@cursor.com> 18 天前
feat(model): add extraBody provider config for request body injection Allow providers to declare an extraBody map in YAML config that gets merged into every outgoing request body, enabling OpenRouter-specific fields like provider.order and allow_fallbacks. Co-authored-by: Cursor <cursoragent@cursor.com> 19 天前