fixes infomaniak download
This commit is contained in:
parent
9816f13ae9
commit
49f3660d89
5 changed files with 68 additions and 10 deletions
|
|
@ -13,6 +13,35 @@ from modules.datamodels.datamodelAi import AiModel, PriorityEnum, ProcessingMode
|
||||||
# Configure logger
|
# Configure logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _supportsCustomTemperature(modelName: str) -> bool:
|
||||||
|
"""Check whether an Anthropic model accepts a custom ``temperature``.
|
||||||
|
|
||||||
|
Anthropic's Extended-Thinking models (Claude 4.7 Opus and the
|
||||||
|
upcoming 4.7 Sonnet/Haiku, plus all 5.x and beyond) reject every
|
||||||
|
``temperature`` value with HTTP 400
|
||||||
|
``{"error": "`temperature` is deprecated for this model."}`` --
|
||||||
|
only the model's internal default is accepted. Older Claude 4.5 /
|
||||||
|
4.6 models still accept any value in [0, 1].
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if ``temperature`` may be sent; False if it must be omitted.
|
||||||
|
"""
|
||||||
|
if not modelName:
|
||||||
|
return True
|
||||||
|
name = modelName.lower()
|
||||||
|
if name.startswith("claude-opus-4-7"):
|
||||||
|
return False
|
||||||
|
if name.startswith("claude-sonnet-4-7"):
|
||||||
|
return False
|
||||||
|
if name.startswith("claude-haiku-4-7"):
|
||||||
|
return False
|
||||||
|
# 5.x and beyond: same Extended-Thinking family, no custom temperature.
|
||||||
|
if name.startswith("claude-opus-5") or name.startswith("claude-sonnet-5") or name.startswith("claude-haiku-5"):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def loadConfigData():
|
def loadConfigData():
|
||||||
"""Load configuration data for Anthropic connector"""
|
"""Load configuration data for Anthropic connector"""
|
||||||
return {
|
return {
|
||||||
|
|
@ -276,8 +305,11 @@ class AiAnthropic(BaseConnectorAi):
|
||||||
payload: Dict[str, Any] = {
|
payload: Dict[str, Any] = {
|
||||||
"model": model.name,
|
"model": model.name,
|
||||||
"messages": converted_messages,
|
"messages": converted_messages,
|
||||||
"temperature": temperature,
|
|
||||||
}
|
}
|
||||||
|
# Extended-Thinking models (claude-opus-4-7 etc.) reject any
|
||||||
|
# `temperature` value -- only the model default is accepted.
|
||||||
|
if _supportsCustomTemperature(model.name):
|
||||||
|
payload["temperature"] = temperature
|
||||||
|
|
||||||
# Anthropic requires max_tokens - use provided value or throw error
|
# Anthropic requires max_tokens - use provided value or throw error
|
||||||
if maxTokens is None:
|
if maxTokens is None:
|
||||||
|
|
@ -381,10 +413,11 @@ class AiAnthropic(BaseConnectorAi):
|
||||||
payload: Dict[str, Any] = {
|
payload: Dict[str, Any] = {
|
||||||
"model": model.name,
|
"model": model.name,
|
||||||
"messages": converted,
|
"messages": converted,
|
||||||
"temperature": temperature,
|
|
||||||
"max_tokens": model.maxTokens,
|
"max_tokens": model.maxTokens,
|
||||||
"stream": True,
|
"stream": True,
|
||||||
}
|
}
|
||||||
|
if _supportsCustomTemperature(model.name):
|
||||||
|
payload["temperature"] = temperature
|
||||||
if system_prompt:
|
if system_prompt:
|
||||||
payload["system"] = system_prompt
|
payload["system"] = system_prompt
|
||||||
if modelCall.tools:
|
if modelCall.tools:
|
||||||
|
|
@ -609,8 +642,8 @@ class AiAnthropic(BaseConnectorAi):
|
||||||
if systemPrompt:
|
if systemPrompt:
|
||||||
payload["system"] = systemPrompt
|
payload["system"] = systemPrompt
|
||||||
|
|
||||||
# Set temperature from model
|
if _supportsCustomTemperature(model.name):
|
||||||
payload["temperature"] = temperature
|
payload["temperature"] = temperature
|
||||||
|
|
||||||
# Make API call with headers from httpClient (which includes anthropic-version)
|
# Make API call with headers from httpClient (which includes anthropic-version)
|
||||||
response = await self.httpClient.post(
|
response = await self.httpClient.post(
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,22 @@ async def _infomaniakDownload(
|
||||||
endpoint: str,
|
endpoint: str,
|
||||||
baseUrl: str = _API_BASE,
|
baseUrl: str = _API_BASE,
|
||||||
) -> Optional[bytes]:
|
) -> Optional[bytes]:
|
||||||
"""Binary download from an Infomaniak host. Returns bytes or ``None``."""
|
"""Binary download from an Infomaniak host. Returns bytes or ``None``.
|
||||||
|
|
||||||
|
Unlike :func:`_infomaniakGet`, this follows redirects: kDrive's
|
||||||
|
``/2/drive/{driveId}/files/{fileId}/download`` answers with
|
||||||
|
``302 -> presigned CDN URL`` (standard for bandwidth-heavy
|
||||||
|
transfers), and the same pattern shows up on Calendar/Contacts
|
||||||
|
export endpoints. Refusing to follow would lose every download.
|
||||||
|
The Authorization header is preserved across the redirect by
|
||||||
|
aiohttp because the host is the same Infomaniak property.
|
||||||
|
"""
|
||||||
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
timeout = aiohttp.ClientTimeout(total=120)
|
timeout = aiohttp.ClientTimeout(total=120)
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||||
async with session.get(url, headers=headers, allow_redirects=False) as resp:
|
async with session.get(url, headers=headers, allow_redirects=True) as resp:
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
return await resp.read()
|
return await resp.read()
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,12 @@ class DataSource(PowerOnModel):
|
||||||
json_schema_extra={"label": "Verbindungs-ID", "fk_target": {"db": "poweron_app", "table": "UserConnection", "labelField": "externalUsername"}},
|
json_schema_extra={"label": "Verbindungs-ID", "fk_target": {"db": "poweron_app", "table": "UserConnection", "labelField": "externalUsername"}},
|
||||||
)
|
)
|
||||||
sourceType: str = Field(
|
sourceType: str = Field(
|
||||||
description="sharepointFolder, googleDriveFolder, outlookFolder, ftpFolder, clickupList (path under /team/...)",
|
description=(
|
||||||
|
"sharepointFolder, onedriveFolder, googleDriveFolder, "
|
||||||
|
"outlookFolder, gmailFolder, ftpFolder, clickupList "
|
||||||
|
"(path under /team/...), kdriveFolder, calendarFolder, "
|
||||||
|
"contactFolder"
|
||||||
|
),
|
||||||
json_schema_extra={"label": "Quellentyp"},
|
json_schema_extra={"label": "Quellentyp"},
|
||||||
)
|
)
|
||||||
path: str = Field(
|
path: str = Field(
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,9 @@ _SOURCE_TYPE_TO_SERVICE = {
|
||||||
"gmailFolder": "gmail",
|
"gmailFolder": "gmail",
|
||||||
"ftpFolder": "files",
|
"ftpFolder": "files",
|
||||||
"clickupList": "clickup",
|
"clickupList": "clickup",
|
||||||
|
"kdriveFolder": "kdrive",
|
||||||
|
"calendarFolder": "calendar",
|
||||||
|
"contactFolder": "contact",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ def _registerDataSourceTools(registry: ToolRegistry, services):
|
||||||
return getattr(chatService, "interfaceDbComponent", None)
|
return getattr(chatService, "interfaceDbComponent", None)
|
||||||
|
|
||||||
# ---- DataSource convenience tools ----
|
# ---- DataSource convenience tools ----
|
||||||
|
# Maps the FE-side `sourceType` literal (see SourcesTab.tsx
|
||||||
|
# `_SERVICE_TO_SOURCE_TYPE`) to the Connector's `service` key in
|
||||||
|
# `_SERVICE_MAP`. Keep this table in sync with both the FE and the
|
||||||
|
# Connector `_SERVICE_MAP` entries -- a missing row produces
|
||||||
|
# "Service '<sourceType>' not available" in the agent tools.
|
||||||
_SOURCE_TYPE_TO_SERVICE = {
|
_SOURCE_TYPE_TO_SERVICE = {
|
||||||
"sharepointFolder": "sharepoint",
|
"sharepointFolder": "sharepoint",
|
||||||
"onedriveFolder": "onedrive",
|
"onedriveFolder": "onedrive",
|
||||||
|
|
@ -45,6 +50,9 @@ def _registerDataSourceTools(registry: ToolRegistry, services):
|
||||||
"gmailFolder": "gmail",
|
"gmailFolder": "gmail",
|
||||||
"ftpFolder": "files",
|
"ftpFolder": "files",
|
||||||
"clickupList": "clickup",
|
"clickupList": "clickup",
|
||||||
|
"kdriveFolder": "kdrive",
|
||||||
|
"calendarFolder": "calendar",
|
||||||
|
"contactFolder": "contact",
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _resolveDataSource(dsId: str):
|
async def _resolveDataSource(dsId: str):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue