licos-dev-sdk 0.4.8__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/PKG-INFO +2 -2
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/pyproject.toml +2 -2
- licos_dev_sdk-0.5.0/src/licos_dev_sdk/langchain_reasoning.py +32 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/model.py +13 -3
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_model.py +24 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/.gitignore +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/DOCX.md +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/__init__.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/_usage_identity.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/_utils.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/archive.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/chart.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/data.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/diagram.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_common.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_edit.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_expectations.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_inspect.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_layout.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_package.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_preservation.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_structure.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_table.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_table_actions.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_read.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_table_export.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/image.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/observability.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/pdf_inspect.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/ppt_master_runtime.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/presentation.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/presentation_canvas.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/presentation_inspect.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/spreadsheet.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/spreadsheet_edit.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/spreadsheet_html.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/spreadsheet_inspect.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/web.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_document_read.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_document_spreadsheet.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_document_table_export.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_docx_inspect.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_docx_structure.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_docx_table_edit.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_html_docx_features.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_langchain_protocol.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_observability.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_output_paths.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_ppt_master_runtime.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_presentation.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_spreadsheet_html_edit.py +0 -0
- {licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/tests/test_usage_identity.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: licos-dev-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: LICOS Dev SDK - file generation and model capability clients
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: beautifulsoup4>=4.12
|
|
7
7
|
Requires-Dist: docxtpl>=0.16
|
|
8
8
|
Requires-Dist: graphviz>=0.20
|
|
9
9
|
Requires-Dist: jinja2>=3.1
|
|
10
|
-
Requires-Dist: licos-platform-sdk>=0.
|
|
10
|
+
Requires-Dist: licos-platform-sdk>=0.6.1
|
|
11
11
|
Requires-Dist: matplotlib>=3.9
|
|
12
12
|
Requires-Dist: mistune>=3.0
|
|
13
13
|
Requires-Dist: openpyxl>=3.1
|
|
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "licos-dev-sdk"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "LICOS Dev SDK - file generation and model capability clients"
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"licos-platform-sdk>=0.
|
|
11
|
+
"licos-platform-sdk>=0.6.1",
|
|
12
12
|
"weasyprint>=62.0",
|
|
13
13
|
"python-docx>=1.1",
|
|
14
14
|
"docxtpl>=0.16",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Preserve provider reasoning fields that ChatOpenAI intentionally omits."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def reasoning_chat_model_class(base_class: type) -> type:
|
|
8
|
+
class ReasoningChatOpenAI(base_class):
|
|
9
|
+
def _convert_chunk_to_generation_chunk(
|
|
10
|
+
self, chunk: dict[str, Any], default_chunk_class: type, base_generation_info: dict[str, Any] | None,
|
|
11
|
+
) -> Any:
|
|
12
|
+
generation = super()._convert_chunk_to_generation_chunk(
|
|
13
|
+
chunk, default_chunk_class, base_generation_info,
|
|
14
|
+
)
|
|
15
|
+
choices = chunk.get("choices") or chunk.get("chunk", {}).get("choices", [])
|
|
16
|
+
if generation is not None and choices:
|
|
17
|
+
delta = choices[0].get("delta") or {}
|
|
18
|
+
reasoning = delta.get("reasoning_content")
|
|
19
|
+
if isinstance(reasoning, str):
|
|
20
|
+
generation.message.additional_kwargs["reasoning_content"] = reasoning
|
|
21
|
+
return generation
|
|
22
|
+
|
|
23
|
+
def _create_chat_result(self, response: Any, generation_info: dict[str, Any] | None = None) -> Any:
|
|
24
|
+
result = super()._create_chat_result(response, generation_info)
|
|
25
|
+
raw = response if isinstance(response, dict) else response.model_dump()
|
|
26
|
+
for choice, generation in zip(raw["choices"], result.generations):
|
|
27
|
+
reasoning = choice["message"].get("reasoning_content")
|
|
28
|
+
if isinstance(reasoning, str):
|
|
29
|
+
generation.message.additional_kwargs["reasoning_content"] = reasoning
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
return ReasoningChatOpenAI
|
|
@@ -7,11 +7,13 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import mimetypes
|
|
9
9
|
import queue
|
|
10
|
+
import re
|
|
10
11
|
import threading
|
|
11
12
|
import time
|
|
12
13
|
import uuid
|
|
13
14
|
from contextvars import ContextVar
|
|
14
15
|
from dataclasses import dataclass, field, replace
|
|
16
|
+
from decimal import Decimal
|
|
15
17
|
from pathlib import Path
|
|
16
18
|
from typing import Any, Callable, Iterator, Sequence
|
|
17
19
|
from urllib import error as urlerror
|
|
@@ -486,6 +488,7 @@ def create_chat_openai(
|
|
|
486
488
|
timeout: int | None = None,
|
|
487
489
|
streaming: bool = True,
|
|
488
490
|
use_responses_api: bool | None = None,
|
|
491
|
+
preserve_reasoning: bool = False,
|
|
489
492
|
default_headers: dict[str, str] | None = None,
|
|
490
493
|
**kwargs: Any,
|
|
491
494
|
) -> Any:
|
|
@@ -496,6 +499,8 @@ def create_chat_openai(
|
|
|
496
499
|
key, so deployed projects do not need LLM_MODEL/OPENAI_MODEL env injection.
|
|
497
500
|
A catalog `response_url` selects Responses by default. Set
|
|
498
501
|
`use_responses_api=False` to use Chat Completions explicitly.
|
|
502
|
+
`preserve_reasoning=True` keeps Chat Completions providers' `reasoning_content`
|
|
503
|
+
in LangChain message metadata for a caller that explicitly forwards it.
|
|
499
504
|
"""
|
|
500
505
|
try:
|
|
501
506
|
from langchain_core.callbacks import BaseCallbackHandler
|
|
@@ -569,6 +574,10 @@ def create_chat_openai(
|
|
|
569
574
|
),
|
|
570
575
|
**kwargs,
|
|
571
576
|
}
|
|
577
|
+
if preserve_reasoning and not use_responses_api:
|
|
578
|
+
from .langchain_reasoning import reasoning_chat_model_class
|
|
579
|
+
|
|
580
|
+
return reasoning_chat_model_class(ChatOpenAI)(**chat_kwargs)
|
|
572
581
|
return ChatOpenAI(**chat_kwargs)
|
|
573
582
|
|
|
574
583
|
|
|
@@ -2511,10 +2520,11 @@ def _int_field(data: dict[str, Any], names: Sequence[str]) -> int | None:
|
|
|
2511
2520
|
parsed = int(value)
|
|
2512
2521
|
return parsed if parsed > 0 else None
|
|
2513
2522
|
if isinstance(value, str):
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
except ValueError:
|
|
2523
|
+
match = re.fullmatch(r"\s*(\d+(?:\.\d+)?)\s*([KMG]?)\s*", value, flags=re.IGNORECASE)
|
|
2524
|
+
if match is None:
|
|
2517
2525
|
continue
|
|
2526
|
+
multiplier = {"": 1, "K": 1000, "M": 1000000, "G": 1000000000}[match.group(2).upper()]
|
|
2527
|
+
parsed = int(Decimal(match.group(1)) * multiplier)
|
|
2518
2528
|
return parsed if parsed > 0 else None
|
|
2519
2529
|
return None
|
|
2520
2530
|
|
|
@@ -821,6 +821,25 @@ class ModelSdkTests(unittest.TestCase):
|
|
|
821
821
|
self.assertEqual(endpoint.max_input_length, 128000)
|
|
822
822
|
self.assertEqual(endpoint.max_output_length, 64000)
|
|
823
823
|
|
|
824
|
+
def test_resolve_llm_endpoint_parses_catalog_limit_suffixes(self) -> None:
|
|
825
|
+
def fake_urlopen(req: Any, timeout: int = 0) -> _FakeResponse:
|
|
826
|
+
if req.full_url == "http://platform.example/api/v1/internal/auth/ai-user-token":
|
|
827
|
+
return _FakeResponse({"code": 0, "success": True, "data": {"accessToken": "user-token"}})
|
|
828
|
+
if _is_available_models_request(req):
|
|
829
|
+
return _available_models_response(req)
|
|
830
|
+
if req.full_url.startswith("http://platform.example/api/v1/admin/workspaces/models/detail?"):
|
|
831
|
+
detail = _model_detail_payload()
|
|
832
|
+
detail["data"].update(contextLength="1M", maxInputLength="991K", maxOutputLength="128K")
|
|
833
|
+
return _FakeResponse(detail)
|
|
834
|
+
raise AssertionError(req.full_url)
|
|
835
|
+
|
|
836
|
+
with mock.patch.object(model.request, "urlopen", fake_urlopen):
|
|
837
|
+
endpoint = model.resolve_llm_endpoint()
|
|
838
|
+
|
|
839
|
+
self.assertEqual(endpoint.context_length, 1000000)
|
|
840
|
+
self.assertEqual(endpoint.max_input_length, 991000)
|
|
841
|
+
self.assertEqual(endpoint.max_output_length, 128000)
|
|
842
|
+
|
|
824
843
|
def test_resolve_llm_endpoint_accepts_explicit_model(self) -> None:
|
|
825
844
|
def fake_urlopen(req: Any, timeout: int = 0) -> _FakeResponse:
|
|
826
845
|
if req.full_url == "http://platform.example/api/v1/internal/auth/ai-user-token":
|
|
@@ -862,9 +881,13 @@ class ModelSdkTests(unittest.TestCase):
|
|
|
862
881
|
with (
|
|
863
882
|
mock.patch.object(model.request, "urlopen", fake_urlopen),
|
|
864
883
|
mock.patch.dict(sys.modules, {"langchain_openai": fake_langchain_openai}),
|
|
884
|
+
mock.patch("httpx.Client", return_value=object()),
|
|
885
|
+
mock.patch("httpx.AsyncClient", return_value=object()),
|
|
865
886
|
):
|
|
866
887
|
chat_model = model.create_chat_openai(
|
|
867
888
|
model="auto",
|
|
889
|
+
preserve_reasoning=True,
|
|
890
|
+
use_responses_api=False,
|
|
868
891
|
temperature=0.2,
|
|
869
892
|
max_completion_tokens=100000,
|
|
870
893
|
timeout=30,
|
|
@@ -875,6 +898,7 @@ class ModelSdkTests(unittest.TestCase):
|
|
|
875
898
|
)
|
|
876
899
|
|
|
877
900
|
self.assertIsInstance(chat_model, FakeChatOpenAI)
|
|
901
|
+
self.assertIsNot(type(chat_model), FakeChatOpenAI)
|
|
878
902
|
self.assertEqual(captured["exchange_headers"]["Authorization"], "Bearer ai-agent-token")
|
|
879
903
|
self.assertEqual(captured["catalog_headers"]["Authorization"], "Bearer user-token")
|
|
880
904
|
self.assertEqual(captured["detail_headers"]["Authorization"], "Bearer user-token")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{licos_dev_sdk-0.4.8 → licos_dev_sdk-0.5.0}/src/licos_dev_sdk/document_docx_table_actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|