diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml
index 6ec949a..f93597e 100644
--- a/.github/workflows/integration_test.yml
+++ b/.github/workflows/integration_test.yml
@@ -28,7 +28,7 @@ jobs:
matrix:
php-versions: [ '8.2' ]
databases: [ 'sqlite' ]
- server-versions: [ 'master', 'stable32', 'stable31' ]
+ server-versions: [ 'master', 'stable33', 'stable32', 'stable31' ]
name: Integration test on ☁️${{ matrix.server-versions }} 🐘${{ matrix.php-versions }}
@@ -198,7 +198,7 @@ jobs:
CREDS: "alice:alice"
run: |
sleep 300
- TASK=$(curl -X POST -u "$CREDS" -H "oCS-APIRequest: true" -H "Content-type: application/json" http://localhost:8080/ocs/v2.php/taskprocessing/schedule?format=json --data-raw '{"input": {"input": "Search duckduckgo for Nextcloud", "confirmation":1, "conversation_token": ""},"type":"core:contextagent:interaction", "appId": "test", "customId": ""}')
+ TASK=$(curl -X POST -u "$CREDS" -H "oCS-APIRequest: true" -H "Content-type: application/json" http://localhost:8080/ocs/v2.php/taskprocessing/schedule?format=json --data-raw '{"input": {"input": "Search youtube for videos about Nextcloud", "confirmation":1, "conversation_token": ""},"type":"core:contextagent:interaction", "appId": "test", "customId": ""}')
echo $TASK
TASK_ID=$(echo $TASK | jq '.ocs.data.task.id')
NEXT_WAIT_TIME=0
@@ -215,7 +215,7 @@ jobs:
[ "$TASK_STATUS" == '"STATUS_SUCCESSFUL"' ]
echo $TASK | jq '.ocs.data.task.output.output'
echo $TASK | jq '.ocs.data.task.output.sources'
- echo $TASK | jq '.ocs.data.task.output.sources' | grep -q 'duckduckgo_results_json'
+ echo $TASK | jq '.ocs.data.task.output.sources' | grep -q 'youtube_search'
echo $TASK | jq '.ocs.data.task.output.output' | grep -q 'Nextcloud'
- name: Show nextcloud logs
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 97a93a7..9bb160a 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -39,7 +39,7 @@ Positive:
https://github.com/nextcloud/context_agent/blob/main/img/screenshot.png?raw=true
https://github.com/nextcloud/context_agent
-
+
diff --git a/ex_app/lib/all_tools/calendar.py b/ex_app/lib/all_tools/calendar.py
index 6ecb1ec..301997e 100644
--- a/ex_app/lib/all_tools/calendar.py
+++ b/ex_app/lib/all_tools/calendar.py
@@ -4,7 +4,7 @@
from time import sleep
from typing import Optional
-import httpx
+from niquests import ConnectionError, Timeout
import pytz
from ics import Calendar, Event, Attendee, Organizer, Todo
from langchain_core.tools import tool
@@ -91,10 +91,8 @@ def schedule_event(calendar_name: str, title: str, description: str, start_date:
json = nc.ocs('GET', '/ocs/v2.php/cloud/user')
break
except (
- httpx.RemoteProtocolError,
- httpx.ReadError,
- httpx.LocalProtocolError,
- httpx.PoolTimeout,
+ ConnectionError,
+ Timeout
) as e:
log(nc, LogLvl.DEBUG, "Ignored error during task polling")
i += 1
diff --git a/ex_app/lib/all_tools/deck.py b/ex_app/lib/all_tools/deck.py
index 4c26b91..cba72bf 100644
--- a/ex_app/lib/all_tools/deck.py
+++ b/ex_app/lib/all_tools/deck.py
@@ -4,7 +4,6 @@
from time import sleep
from typing import Optional
-import httpx
import pytz
from langchain_core.tools import tool
from nc_py_api import Nextcloud
diff --git a/ex_app/lib/all_tools/here.py b/ex_app/lib/all_tools/here.py
index 887ff1a..be44df8 100644
--- a/ex_app/lib/all_tools/here.py
+++ b/ex_app/lib/all_tools/here.py
@@ -4,7 +4,7 @@
import datetime
import urllib.parse
-import httpx
+import niquests
from langchain_core.tools import tool
from nc_py_api import Nextcloud
@@ -30,7 +30,7 @@ def get_public_transport_route_for_coordinates(origin_lat: str, origin_lon: str,
if departure_time is None:
departure_time = urllib.parse.quote_plus(datetime.datetime.now(datetime.UTC).isoformat())
api_key = nc.appconfig_ex.get_value('here_api')
- res = httpx.get('https://transit.hereapi.com/v8/routes?transportMode=car&origin='
+ res = niquests.get('https://transit.hereapi.com/v8/routes?transportMode=car&origin='
+ origin_lat + ',' + origin_lon + '&destination=' + destination_lat + ',' + destination_lon
+ '&alternatives=' + str(routes-1) + '&departureTime=' + departure_time + '&apikey=' + api_key)
json = res.json()
diff --git a/ex_app/lib/all_tools/lib/task_processing.py b/ex_app/lib/all_tools/lib/task_processing.py
index 770eef6..59e226c 100644
--- a/ex_app/lib/all_tools/lib/task_processing.py
+++ b/ex_app/lib/all_tools/lib/task_processing.py
@@ -3,7 +3,7 @@
import time
import typing
-import httpx
+from niquests import ConnectionError, Timeout
from nc_py_api import NextcloudException
from nc_py_api.ex_app import LogLvl
from pydantic import BaseModel, ValidationError
@@ -20,11 +20,24 @@ class Response(BaseModel):
task: Task
def run_task(nc, type, task_input):
- response = nc.ocs(
- "POST",
- "/ocs/v1.php/taskprocessing/schedule",
- json={"type": type, "appId": "context_agent", "input": task_input},
- )
+ i = 0
+ while i < 20:
+ try:
+ response = nc.ocs(
+ "POST",
+ "/ocs/v1.php/taskprocessing/schedule",
+ json={"type": type, "appId": "context_agent", "input": task_input},
+ )
+ break
+ except (
+ ConnectionError,
+ Timeout
+
+ ) as e:
+ log(nc, LogLvl.DEBUG, "Ignored error during task scheduling")
+ i += 1
+ sleep(1)
+ continue
try:
task = Response.model_validate(response).task
@@ -38,10 +51,8 @@ def run_task(nc, type, task_input):
try:
response = nc.ocs("GET", f"/ocs/v1.php/taskprocessing/task/{task.id}")
except (
- httpx.RemoteProtocolError,
- httpx.ReadError,
- httpx.LocalProtocolError,
- httpx.PoolTimeout,
+ ConnectionError,
+ Timeout
) as e:
log(nc, LogLvl.DEBUG, "Ignored error during task polling")
time.sleep(5)
diff --git a/ex_app/lib/all_tools/mail.py b/ex_app/lib/all_tools/mail.py
index 38a99a2..c37109e 100644
--- a/ex_app/lib/all_tools/mail.py
+++ b/ex_app/lib/all_tools/mail.py
@@ -2,7 +2,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
from time import sleep
-import httpx
+from niquests import ConnectionError, Timeout
from langchain_core.tools import tool
from nc_py_api import Nextcloud
from nc_py_api.ex_app import LogLvl
@@ -35,10 +35,8 @@ def send_email(subject: str, body: str, account_id: int, from_email: str, to_ema
'to': [{'label': '', 'email': email} for email in to_emails],
})
except (
- httpx.RemoteProtocolError,
- httpx.ReadError,
- httpx.LocalProtocolError,
- httpx.PoolTimeout,
+ ConnectionError,
+ Timeout
) as e:
log(nc, LogLvl.DEBUG, "Ignored error during task polling")
i += 1
diff --git a/ex_app/lib/all_tools/openstreetmap.py b/ex_app/lib/all_tools/openstreetmap.py
index 4c910a3..028ac24 100644
--- a/ex_app/lib/all_tools/openstreetmap.py
+++ b/ex_app/lib/all_tools/openstreetmap.py
@@ -6,7 +6,7 @@
import urllib.parse
from time import sleep
-import httpx
+import niquests
from langchain_core.tools import tool
from nc_py_api import Nextcloud
@@ -22,7 +22,7 @@ def get_coordinates_for_address(address: str) -> (str, str):
:param address: the address to calculate the coordinates for
:return: a tuple of latitude and longitude
"""
- res = httpx.get('https://nominatim.openstreetmap.org/search', params={'q': address, 'format': 'json', 'addressdetails': '1', 'extratags': '1', 'namedetails': '1', 'limit': '1'})
+ res = niquests.get('https://nominatim.openstreetmap.org/search', params={'q': address, 'format': 'json', 'addressdetails': '1', 'extratags': '1', 'namedetails': '1', 'limit': '1'})
json = res.json()
if 'error' in json:
raise Exception(json['error'])
@@ -56,7 +56,7 @@ def get_osm_route(profile: str, origin_lat: str, origin_lon: str, destination_la
profile_num = "2"
url = f'https://routing.openstreetmap.de/{profile}/route/v1/driving/{origin_lon},{origin_lat};{destination_lon},{destination_lat}?overview=false&steps=true'
map_url = f' https://routing.openstreetmap.de/?loc={origin_lat}%2C{origin_lon}&loc={destination_lat}%2C{destination_lon}&srv={profile_num}'
- res = httpx.get(url)
+ res = niquests.get(url)
json = res.json()
return {'route_json_description': json, 'map_url': map_url}
@@ -70,7 +70,7 @@ def get_osm_link(location: str):
:return: URL
"""
- res = httpx.get('https://nominatim.openstreetmap.org/search', params={'q': location, 'format': 'json','limit': '1'})
+ res = niquests.get('https://nominatim.openstreetmap.org/search', params={'q': location, 'format': 'json','limit': '1'})
json = res.json()
if 'error' in json:
raise Exception(json['error'])
diff --git a/ex_app/lib/all_tools/weather.py b/ex_app/lib/all_tools/weather.py
index 7bc59fa..db420ae 100644
--- a/ex_app/lib/all_tools/weather.py
+++ b/ex_app/lib/all_tools/weather.py
@@ -3,7 +3,7 @@
import typing
import urllib.parse
-import httpx
+import niquests
from langchain_core.tools import tool
from nc_py_api import Nextcloud
@@ -20,7 +20,7 @@ def get_current_weather_for_coordinates(lat: str, lon: str) -> dict[str, typing.
:param lon: Longitude
:return:
"""
- res = httpx.get('https://api.met.no/weatherapi/locationforecast/2.0/compact', params={
+ res = niquests.get('https://api.met.no/weatherapi/locationforecast/2.0/compact', params={
'lat': lat,
'lon': lon,
},
diff --git a/ex_app/lib/nc_model.py b/ex_app/lib/nc_model.py
index c917654..cf2d6cb 100644
--- a/ex_app/lib/nc_model.py
+++ b/ex_app/lib/nc_model.py
@@ -5,7 +5,7 @@
import typing
from typing import Optional, Any, Sequence, Union, Callable
-import httpx
+from niquests import ConnectionError, Timeout
from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.language_models import LanguageModelInput
from langchain_core.messages import BaseMessage, AIMessage
@@ -90,11 +90,24 @@ def _generate(
log(nc, LogLvl.DEBUG, task_input)
- response = nc.ocs(
- "POST",
- "/ocs/v1.php/taskprocessing/schedule",
- json={"type": "core:text2text:chatwithtools", "appId": "context_agent", "input": task_input},
- )
+ i = 0
+ while i < 20:
+ try:
+ response = nc.ocs(
+ "POST",
+ "/ocs/v1.php/taskprocessing/schedule",
+ json={"type": "core:text2text:chatwithtools", "appId": "context_agent", "input": task_input},
+ )
+ break
+ except (
+ ConnectionError,
+ Timeout
+
+ ) as e:
+ log(nc, LogLvl.DEBUG, "Ignored error during task scheduling")
+ i += 1
+ sleep(1)
+ continue
try:
task = Response.model_validate(response).task
@@ -109,10 +122,9 @@ def _generate(
try:
response = nc.ocs("GET", f"/ocs/v1.php/taskprocessing/task/{task.id}")
except (
- httpx.RemoteProtocolError,
- httpx.ReadError,
- httpx.LocalProtocolError,
- httpx.PoolTimeout,
+ ConnectionError,
+ Timeout
+
) as e:
log(nc, LogLvl.DEBUG, "Ignored error during task polling")
time.sleep(5)
diff --git a/poetry.lock b/poetry.lock
index 261baa1..0898c53 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -2110,14 +2110,14 @@ docs = ["autodoc-pydantic (>=2.0.1)", "caldav (==1.3.6)", "sphinx (<8)", "sphinx
[[package]]
name = "niquests"
-version = "3.15.2"
+version = "3.17.0"
description = "Niquests is a simple, yet elegant, HTTP library. It is a drop-in replacement for Requests, which is under feature freeze."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
- {file = "niquests-3.15.2-py3-none-any.whl", hash = "sha256:2446e3602ba1418434822f5c1fcf8b8d1b52a3c296d2808a1ab7de4cf1312d99"},
- {file = "niquests-3.15.2.tar.gz", hash = "sha256:8076b1d2ff957022d52b2216ca7df92d92ce426d19a7ed63c7fd4fd630ab6c2b"},
+ {file = "niquests-3.17.0-py3-none-any.whl", hash = "sha256:3930d94fce367385950dd545f913e7cfc6457feda76aecafeb324aae45da9fe1"},
+ {file = "niquests-3.17.0.tar.gz", hash = "sha256:1f4f337a973215c76f6f6471504fedab9dc6187203284146081e1bd3d2a311fc"},
]
[package.dependencies]
@@ -4257,4 +4257,4 @@ cffi = ["cffi (>=1.11)"]
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
-content-hash = "dece81e5f1b7f2d561d0c3b2478eeb5e2032d1b6157c37b9d6aa11a0a3fc7ec3"
+content-hash = "f5266cfc8797e210c471b6c96ba26325608a9e1ac1930dcbcdab8030d888f760"
diff --git a/pyproject.toml b/pyproject.toml
index dabc422..8e90793 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,6 +22,7 @@ duckduckgo-search = "^8.0.1"
uvicorn = "^0.34.2"
langchain-mcp-adapters = "^0.1.9"
fastmcp = "^2.11.2"
+niquests = "^3.17.0"
[build-system]
requires = ["poetry-core"]