|
5 | 5 | funding_url: https://github.com/open-webui |
6 | 6 | openwebui_id: ce96f7b4-12fc-4ac3-9a01-875713e69359 |
7 | 7 | description: Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging. |
8 | | -version: 0.6.0 |
| 8 | +version: 0.6.1 |
9 | 9 | requirements: github-copilot-sdk==0.1.23 |
10 | 10 | """ |
11 | 11 |
|
@@ -1753,75 +1753,82 @@ def _get_chat_context( |
1753 | 1753 | "chat_id": str(chat_id).strip(), |
1754 | 1754 | } |
1755 | 1755 |
|
1756 | | - async def _fetch_byok_models(self) -> List[dict]: |
| 1756 | + async def _fetch_byok_models(self, uv: "Pipe.UserValves" = None) -> List[dict]: |
1757 | 1757 | """Fetch BYOK models from configured provider.""" |
1758 | 1758 | model_list = [] |
1759 | | - if self.valves.BYOK_BASE_URL: |
| 1759 | + |
| 1760 | + # Resolve effective settings (User > Global) |
| 1761 | + # Note: We handle the case where uv might be None |
| 1762 | + effective_base_url = (uv.BYOK_BASE_URL if uv else "") or self.valves.BYOK_BASE_URL |
| 1763 | + effective_type = (uv.BYOK_TYPE if uv else "") or self.valves.BYOK_TYPE |
| 1764 | + effective_api_key = (uv.BYOK_API_KEY if uv else "") or self.valves.BYOK_API_KEY |
| 1765 | + effective_bearer_token = (uv.BYOK_BEARER_TOKEN if uv else "") or self.valves.BYOK_BEARER_TOKEN |
| 1766 | + effective_models = (uv.BYOK_MODELS if uv else "") or self.valves.BYOK_MODELS |
| 1767 | + |
| 1768 | + if effective_base_url: |
1760 | 1769 | try: |
1761 | | - base_url = self.valves.BYOK_BASE_URL.rstrip("/") |
| 1770 | + base_url = effective_base_url.rstrip("/") |
1762 | 1771 | url = f"{base_url}/models" |
1763 | 1772 | headers = {} |
1764 | | - provider_type = self.valves.BYOK_TYPE.lower() |
| 1773 | + provider_type = effective_type.lower() |
1765 | 1774 |
|
1766 | 1775 | if provider_type == "anthropic": |
1767 | | - if self.valves.BYOK_API_KEY: |
1768 | | - headers["x-api-key"] = self.valves.BYOK_API_KEY |
| 1776 | + if effective_api_key: |
| 1777 | + headers["x-api-key"] = effective_api_key |
1769 | 1778 | headers["anthropic-version"] = "2023-06-01" |
1770 | 1779 | else: |
1771 | | - if self.valves.BYOK_BEARER_TOKEN: |
| 1780 | + if effective_bearer_token: |
1772 | 1781 | headers["Authorization"] = ( |
1773 | | - f"Bearer {self.valves.BYOK_BEARER_TOKEN}" |
| 1782 | + f"Bearer {effective_bearer_token}" |
1774 | 1783 | ) |
1775 | | - elif self.valves.BYOK_API_KEY: |
1776 | | - headers["Authorization"] = f"Bearer {self.valves.BYOK_API_KEY}" |
| 1784 | + elif effective_api_key: |
| 1785 | + headers["Authorization"] = f"Bearer {effective_api_key}" |
1777 | 1786 |
|
1778 | | - timeout = aiohttp.ClientTimeout(total=5) |
| 1787 | + timeout = aiohttp.ClientTimeout(total=60) |
1779 | 1788 | async with aiohttp.ClientSession(timeout=timeout) as session: |
1780 | | - async with session.get(url, headers=headers) as resp: |
1781 | | - if resp.status == 200: |
1782 | | - data = await resp.json() |
1783 | | - if ( |
1784 | | - isinstance(data, dict) |
1785 | | - and "data" in data |
1786 | | - and isinstance(data["data"], list) |
1787 | | - ): |
1788 | | - for item in data["data"]: |
1789 | | - if isinstance(item, dict) and "id" in item: |
1790 | | - model_list.append(item["id"]) |
1791 | | - await self._emit_debug_log( |
1792 | | - f"BYOK: Fetched {len(model_list)} models from {url}" |
1793 | | - ) |
1794 | | - else: |
1795 | | - await self._emit_debug_log( |
1796 | | - f"BYOK: Failed to fetch models from {url}. Status: {resp.status}" |
1797 | | - ) |
| 1789 | + for attempt in range(3): |
| 1790 | + try: |
| 1791 | + async with session.get(url, headers=headers) as resp: |
| 1792 | + if resp.status == 200: |
| 1793 | + data = await resp.json() |
| 1794 | + if ( |
| 1795 | + isinstance(data, dict) |
| 1796 | + and "data" in data |
| 1797 | + and isinstance(data["data"], list) |
| 1798 | + ): |
| 1799 | + for item in data["data"]: |
| 1800 | + if isinstance(item, dict) and "id" in item: |
| 1801 | + model_list.append(item["id"]) |
| 1802 | + elif isinstance(data, list): |
| 1803 | + for item in data: |
| 1804 | + if isinstance(item, dict) and "id" in item: |
| 1805 | + model_list.append(item["id"]) |
| 1806 | + |
| 1807 | + await self._emit_debug_log( |
| 1808 | + f"BYOK: Fetched {len(model_list)} models from {url}" |
| 1809 | + ) |
| 1810 | + break |
| 1811 | + else: |
| 1812 | + await self._emit_debug_log( |
| 1813 | + f"BYOK: Failed to fetch models from {url} (Attempt {attempt+1}/3). Status: {resp.status}" |
| 1814 | + ) |
| 1815 | + except Exception as e: |
| 1816 | + await self._emit_debug_log(f"BYOK: Model fetch error (Attempt {attempt+1}/3): {e}") |
| 1817 | + |
| 1818 | + if attempt < 2: |
| 1819 | + await asyncio.sleep(1) |
1798 | 1820 | except Exception as e: |
1799 | | - await self._emit_debug_log(f"BYOK: Model fetch error: {e}") |
| 1821 | + await self._emit_debug_log(f"BYOK: Setup error: {e}") |
1800 | 1822 |
|
1801 | 1823 | # Fallback to configured list or defaults |
1802 | 1824 | if not model_list: |
1803 | | - if self.valves.BYOK_MODELS.strip(): |
| 1825 | + if effective_models.strip(): |
1804 | 1826 | model_list = [ |
1805 | | - m.strip() for m in self.valves.BYOK_MODELS.split(",") if m.strip() |
| 1827 | + m.strip() for m in effective_models.split(",") if m.strip() |
1806 | 1828 | ] |
1807 | 1829 | await self._emit_debug_log( |
1808 | 1830 | f"BYOK: Using user-configured BYOK_MODELS ({len(model_list)} models)." |
1809 | 1831 | ) |
1810 | | - else: |
1811 | | - defaults = { |
1812 | | - "anthropic": [ |
1813 | | - "claude-3-5-sonnet-latest", |
1814 | | - "claude-3-5-haiku-latest", |
1815 | | - "claude-3-opus-latest", |
1816 | | - ], |
1817 | | - } |
1818 | | - model_list = defaults.get( |
1819 | | - self.valves.BYOK_TYPE.lower(), |
1820 | | - ["gpt-4o", "gpt-4o-mini", "claude-3-5-sonnet-latest"], |
1821 | | - ) |
1822 | | - await self._emit_debug_log( |
1823 | | - f"BYOK: Using default fallback models for {self.valves.BYOK_TYPE} ({len(model_list)} models)." |
1824 | | - ) |
1825 | 1832 |
|
1826 | 1833 | return [ |
1827 | 1834 | { |
@@ -1943,13 +1950,14 @@ async def pipes(self, __user__: Optional[dict] = None) -> List[dict]: |
1943 | 1950 |
|
1944 | 1951 | # Fetch BYOK models if configured |
1945 | 1952 | byok = [] |
1946 | | - if self.valves.BYOK_BASE_URL and ( |
| 1953 | + effective_base_url = uv.BYOK_BASE_URL or self.valves.BYOK_BASE_URL |
| 1954 | + if effective_base_url and ( |
1947 | 1955 | uv.BYOK_API_KEY |
1948 | 1956 | or self.valves.BYOK_API_KEY |
1949 | 1957 | or uv.BYOK_BEARER_TOKEN |
1950 | 1958 | or self.valves.BYOK_BEARER_TOKEN |
1951 | 1959 | ): |
1952 | | - byok = await self._fetch_byok_models() |
| 1960 | + byok = await self._fetch_byok_models(uv=uv) |
1953 | 1961 |
|
1954 | 1962 | standard = [] |
1955 | 1963 | if token: |
|
0 commit comments