Compare commits

...

12 Commits

Author SHA1 Message Date
rkuo-danswer
decd31c65a Merge pull request #2976 from danswer-ai/hotfix/v0.10-tenant-redis-methods
Merge hotfix/v0.10-tenant-redis-methods into release/v0.10
2024-10-28 18:16:55 -07:00
Richard Kuo
f0adc03de3 backport structured json fix 2024-10-28 17:22:21 -07:00
Richard Kuo (Danswer)
c07a10440b add missing scard operation 2024-10-28 16:37:25 -07:00
pablodanswer
ca4b230f67 add srem and sadd to tenant wrapper (#2973) 2024-10-28 22:43:44 +00:00
Yuhong Sun
4479bdceab Backport Test 7 (#2971) 2024-10-28 05:55:55 +00:00
Yuhong Sun
e23a37e3f1 Backport Test 5 (#2969) 2024-10-28 03:07:41 +00:00
Yuhong Sun
eadd87363d Backport Test 4 (#2968) 2024-10-28 02:41:18 +00:00
Yuhong Sun
91d9414ada Backport Test (#2958) 2024-10-27 23:06:50 +00:00
Yuhong Sun
39a485b777 Backport Test (#2957) 2024-10-27 22:55:20 +00:00
Yuhong Sun
35e4ba7f99 Harmless Backport Test (#2950) 2024-10-27 21:49:24 +00:00
Yuhong Sun
302d28f1e8 Backport Test Final (#2942) 2024-10-26 22:10:14 +00:00
Yuhong Sun
7e8e89359d Backport Test (#2940) 2024-10-26 21:26:59 +00:00
11 changed files with 57 additions and 27 deletions

View File

@@ -31,6 +31,12 @@ def upgrade() -> None:
def downgrade() -> None:
# First, update any null values to a default value
op.execute(
"UPDATE connector_credential_pair SET last_attempt_status = 'NOT_STARTED' WHERE last_attempt_status IS NULL"
)
# Then, make the column non-nullable
op.alter_column(
"connector_credential_pair",
"last_attempt_status",

View File

@@ -96,6 +96,7 @@ from danswer.utils.variable_functionality import fetch_versioned_implementation
from shared_configs.configs import CURRENT_TENANT_ID_CONTEXTVAR
from shared_configs.configs import POSTGRES_DEFAULT_SCHEMA
logger = setup_logger()

View File

@@ -28,6 +28,7 @@ from danswer.utils.logger import PlainFormatter
from danswer.utils.logger import setup_logger
from shared_configs.configs import SENTRY_DSN
logger = setup_logger()
task_logger = get_task_logger(__name__)

View File

@@ -24,6 +24,10 @@ from danswer.connectors.models import Document
from danswer.connectors.models import Section
from danswer.utils.logger import setup_logger
logger = setup_logger()
# List of directories/Files to exclude
exclude_patterns = [
"logs",
@@ -31,7 +35,6 @@ exclude_patterns = [
".gitlab/",
".pre-commit-config.yaml",
]
logger = setup_logger()
def _batch_gitlab_objects(

View File

@@ -22,6 +22,7 @@ from danswer.connectors.models import Document
from danswer.connectors.models import Section
from danswer.utils.logger import setup_logger
logger = setup_logger()
@@ -230,5 +231,7 @@ if __name__ == "__main__":
print("All docs", all_docs)
current = datetime.datetime.now().timestamp()
one_day_ago = current - 30 * 24 * 60 * 60 # 30 days
latest_docs = list(test_connector.poll_source(one_day_ago, current))
print("Latest docs", latest_docs)

View File

@@ -20,10 +20,13 @@ from danswer.connectors.models import Document
from danswer.connectors.models import Section
from danswer.utils.logger import setup_logger
logger = setup_logger()
# Fairly generous retry because it's not understood why occasionally GraphQL requests fail even with timeout > 1 min
SLAB_GRAPHQL_MAX_TRIES = 10
SLAB_API_URL = "https://api.slab.com/v1/graphql"
logger = setup_logger()
def run_graphql_request(

View File

@@ -441,6 +441,7 @@ if __name__ == "__main__":
current = time.time()
one_day_ago = current - 24 * 60 * 60 # 1 day
document_batches = connector.poll_source(one_day_ago, current)
print(next(document_batches))

View File

@@ -237,6 +237,7 @@ class Answer:
prompt=prompt,
tools=final_tool_definitions if final_tool_definitions else None,
tool_choice="required" if self.force_use_tool.force_use else None,
structured_response_format=self.answer_style_config.structured_response_format,
):
if isinstance(message, AIMessageChunk) and (
message.tool_call_chunks or message.tool_calls
@@ -331,7 +332,10 @@ class Answer:
tool_choice: ToolChoiceOptions | None = None,
) -> Iterator[str | StreamStopInfo]:
for message in self.llm.stream(
prompt=prompt, tools=tools, tool_choice=tool_choice
prompt=prompt,
tools=tools,
tool_choice=tool_choice,
structured_response_format=self.answer_style_config.structured_response_format,
):
if isinstance(message, AIMessageChunk):
if message.content:

View File

@@ -102,6 +102,9 @@ class TenantRedis(redis.Redis):
"reacquire",
"create_lock",
"startswith",
"sadd",
"srem",
"scard",
] # Regular methods that need simple prefixing
if item == "scan_iter":

View File

@@ -154,42 +154,38 @@ def test_send_message_simple_with_history_strict_json(
new_admin_user: DATestUser | None,
) -> None:
# create connectors
cc_pair_1: DATestCCPair = CCPairManager.create_from_scratch(
user_performing_action=new_admin_user,
)
api_key: DATestAPIKey = APIKeyManager.create(
user_performing_action=new_admin_user,
)
LLMProviderManager.create(user_performing_action=new_admin_user)
cc_pair_1.documents = DocumentManager.seed_dummy_docs(
cc_pair=cc_pair_1,
num_docs=NUM_DOCS,
api_key=api_key,
)
response = requests.post(
f"{API_SERVER_URL}/chat/send-message-simple-with-history",
json={
# intentionally not relevant prompt to ensure that the
# structured response format is actually used
"messages": [
{
"message": "List the names of the first three US presidents in JSON format",
"message": "What is green?",
"role": MessageType.USER.value,
}
],
"persona_id": 0,
"prompt_id": 0,
"structured_response_format": {
"type": "json_object",
"schema": {
"type": "object",
"properties": {
"presidents": {
"type": "array",
"items": {"type": "string"},
"description": "List of the first three US presidents",
}
"type": "json_schema",
"json_schema": {
"name": "presidents",
"schema": {
"type": "object",
"properties": {
"presidents": {
"type": "array",
"items": {"type": "string"},
"description": "List of the first three US presidents",
}
},
"required": ["presidents"],
"additionalProperties": False,
},
"required": ["presidents"],
"strict": True,
},
},
},
@@ -211,14 +207,17 @@ def test_send_message_simple_with_history_strict_json(
try:
clean_answer = clean_json_string(response_json["answer"])
parsed_answer = json.loads(clean_answer)
# NOTE: do not check content, just the structure
assert isinstance(parsed_answer, dict)
assert "presidents" in parsed_answer
assert isinstance(parsed_answer["presidents"], list)
assert len(parsed_answer["presidents"]) == 3
for president in parsed_answer["presidents"]:
assert isinstance(president, str)
except json.JSONDecodeError:
assert False, "The answer is not a valid JSON object"
assert (
False
), f"The answer is not a valid JSON object - '{response_json['answer']}'"
# Check that the answer_citationless is also valid JSON
assert "answer_citationless" in response_json

View File

@@ -9,12 +9,15 @@ from pytest_mock import MockFixture
from danswer.connectors.mediawiki import wiki
# These tests are disabled for now
@pytest.fixture
def site() -> pywikibot.Site:
return pywikibot.Site("en", "wikipedia")
@pytest.mark.skip(reason="Test disabled")
def test_pywikibot_timestamp_to_utc_datetime() -> None:
timestamp_without_tzinfo = pywikibot.Timestamp(2023, 12, 27, 15, 38, 49)
timestamp_min_timezone = timestamp_without_tzinfo.astimezone(datetime.timezone.min)
@@ -80,6 +83,7 @@ class MockPage(pywikibot.Page):
)
@pytest.mark.skip(reason="Test disabled")
def test_get_doc_from_page(site: pywikibot.Site) -> None:
test_page = MockPage(site, "Test Page", _has_categories=True)
doc = wiki.get_doc_from_page(test_page, site, wiki.DocumentSource.MEDIAWIKI)
@@ -103,6 +107,7 @@ def test_get_doc_from_page(site: pywikibot.Site) -> None:
assert doc.id == f"MEDIAWIKI_{test_page.pageid}_{test_page.full_url()}"
@pytest.mark.skip(reason="Test disabled")
def test_mediawiki_connector_recurse_depth() -> None:
"""Test that the recurse_depth parameter is parsed correctly.
@@ -132,6 +137,7 @@ def test_mediawiki_connector_recurse_depth() -> None:
assert connector.recurse_depth == recurse_depth
@pytest.mark.skip(reason="Test disabled")
def test_load_from_state_calls_poll_source_with_nones(mocker: MockFixture) -> None:
connector = wiki.MediaWikiConnector("wikipedia.org", [], [], 0, "test")
poll_source = mocker.patch.object(connector, "poll_source")