msgflux 0.1.0a1__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.
- msgflux-0.1.0a1/.github/CODEOWNERS +5 -0
- msgflux-0.1.0a1/.github/dependabot.yml +7 -0
- msgflux-0.1.0a1/.github/workflows/publish.yml +119 -0
- msgflux-0.1.0a1/.gitignore +25 -0
- msgflux-0.1.0a1/.pre-commit-config.yaml +19 -0
- msgflux-0.1.0a1/.readthedocs.yaml +12 -0
- msgflux-0.1.0a1/LICENSE +21 -0
- msgflux-0.1.0a1/PKG-INFO +45 -0
- msgflux-0.1.0a1/README.md +1 -0
- msgflux-0.1.0a1/pyproject.toml +141 -0
- msgflux-0.1.0a1/src/msgflux/__init__.py +37 -0
- msgflux-0.1.0a1/src/msgflux/_private/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/_private/client.py +91 -0
- msgflux-0.1.0a1/src/msgflux/_private/core.py +14 -0
- msgflux-0.1.0a1/src/msgflux/_private/executor.py +77 -0
- msgflux-0.1.0a1/src/msgflux/cache.py +50 -0
- msgflux-0.1.0a1/src/msgflux/data/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/audio.py +1 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/base.py +32 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/database.py +125 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/providers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/providers/cachetools.py +64 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/providers/diskcache.py +60 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/providers/faiss.py +217 -0
- msgflux-0.1.0a1/src/msgflux/data/databases/types.py +20 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/base.py +11 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/parser.py +88 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/providers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/providers/openpyxl.py +166 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/providers/pypdf.py +49 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/providers/python_pptx.py +167 -0
- msgflux-0.1.0a1/src/msgflux/data/parsers/types.py +23 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/base.py +12 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/providers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/providers/bm25.py +188 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/providers/rank_bm25.py +187 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/retriever.py +80 -0
- msgflux-0.1.0a1/src/msgflux/data/retrievers/types.py +15 -0
- msgflux-0.1.0a1/src/msgflux/dotdict.py +169 -0
- msgflux-0.1.0a1/src/msgflux/dsl/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/dsl/inline.py +524 -0
- msgflux-0.1.0a1/src/msgflux/dsl/signature.py +400 -0
- msgflux-0.1.0a1/src/msgflux/envs.py +106 -0
- msgflux-0.1.0a1/src/msgflux/exceptions.py +31 -0
- msgflux-0.1.0a1/src/msgflux/generation/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/generation/reasoning/__init__.py +6 -0
- msgflux-0.1.0a1/src/msgflux/generation/reasoning/cot.py +70 -0
- msgflux-0.1.0a1/src/msgflux/generation/reasoning/react.py +47 -0
- msgflux-0.1.0a1/src/msgflux/generation/reasoning/self_consistency.py +42 -0
- msgflux-0.1.0a1/src/msgflux/generation/reasoning/tot.py +57 -0
- msgflux-0.1.0a1/src/msgflux/generation/templates.py +87 -0
- msgflux-0.1.0a1/src/msgflux/logger.py +148 -0
- msgflux-0.1.0a1/src/msgflux/message.py +43 -0
- msgflux-0.1.0a1/src/msgflux/models/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/models/base.py +31 -0
- msgflux-0.1.0a1/src/msgflux/models/gateway.py +242 -0
- msgflux-0.1.0a1/src/msgflux/models/httpx.py +39 -0
- msgflux-0.1.0a1/src/msgflux/models/model.py +170 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/base.py +123 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/ctranslate2.py +144 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/jinaai.py +237 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/mistral.py +1 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/ollama.py +34 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/openai.py +955 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/openrouter.py +20 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/pylate.py +0 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/sambanova.py +32 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/timm.py +64 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/together.py +45 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/torchaudio.py +74 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/torchvision.py +120 -0
- msgflux-0.1.0a1/src/msgflux/models/providers/vllm.py +86 -0
- msgflux-0.1.0a1/src/msgflux/models/response.py +76 -0
- msgflux-0.1.0a1/src/msgflux/models/tool_call_agg.py +93 -0
- msgflux-0.1.0a1/src/msgflux/models/types.py +180 -0
- msgflux-0.1.0a1/src/msgflux/nn/__init__.py +7 -0
- msgflux-0.1.0a1/src/msgflux/nn/functional.py +472 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/__init__.py +23 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/agent.py +1005 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/container.py +601 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/designer.py +273 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/module.py +1958 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/predictor.py +116 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/retriever.py +245 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/speaker.py +140 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/tool.py +296 -0
- msgflux-0.1.0a1/src/msgflux/nn/modules/transcriber.py +181 -0
- msgflux-0.1.0a1/src/msgflux/nn/parameter.py +75 -0
- msgflux-0.1.0a1/src/msgflux/py.typed +0 -0
- msgflux-0.1.0a1/src/msgflux/telemetry/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/telemetry/span.py +141 -0
- msgflux-0.1.0a1/src/msgflux/telemetry/tracer.py +48 -0
- msgflux-0.1.0a1/src/msgflux/utils/__init__.py +0 -0
- msgflux-0.1.0a1/src/msgflux/utils/chat.py +508 -0
- msgflux-0.1.0a1/src/msgflux/utils/common.py +25 -0
- msgflux-0.1.0a1/src/msgflux/utils/convert.py +41 -0
- msgflux-0.1.0a1/src/msgflux/utils/encode.py +101 -0
- msgflux-0.1.0a1/src/msgflux/utils/hooks.py +68 -0
- msgflux-0.1.0a1/src/msgflux/utils/imports.py +39 -0
- msgflux-0.1.0a1/src/msgflux/utils/inspect.py +110 -0
- msgflux-0.1.0a1/src/msgflux/utils/logging.py +15 -0
- msgflux-0.1.0a1/src/msgflux/utils/mermaid.py +11 -0
- msgflux-0.1.0a1/src/msgflux/utils/msgspec.py +489 -0
- msgflux-0.1.0a1/src/msgflux/utils/pooling.py +45 -0
- msgflux-0.1.0a1/src/msgflux/utils/tenacity.py +19 -0
- msgflux-0.1.0a1/src/msgflux/utils/tool.py +121 -0
- msgflux-0.1.0a1/src/msgflux/utils/torch.py +8 -0
- msgflux-0.1.0a1/src/msgflux/utils/validation.py +22 -0
- msgflux-0.1.0a1/src/msgflux/utils/xml.py +125 -0
- msgflux-0.1.0a1/src/msgflux/version.py +1 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Dynamic run name that appears in the GitHub UI
|
|
4
|
+
run-name: Release version ${{ github.ref_name }} of the SDK
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
# no explicit inputs for tag_name; rely on the selected reference from the UI
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
# ensures only a single instance of this release workflow is running at any one time
|
|
11
|
+
concurrency:
|
|
12
|
+
group: release-${{ github.ref_name }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
PACKAGE_NAME: "msgspec-ext"
|
|
17
|
+
TEST_PYPI_URL: "https://test.pypi.org/pypi"
|
|
18
|
+
PYPI_URL: "https://pypi.org/pypi"
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
get_tag_details:
|
|
22
|
+
name: Get Tag Details
|
|
23
|
+
runs-on: msgflux-python-runner
|
|
24
|
+
outputs:
|
|
25
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
26
|
+
new_version: ${{ steps.release.outputs.new_version }}
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0 # fetch all history
|
|
31
|
+
|
|
32
|
+
- name: Check if a tag is selected
|
|
33
|
+
run: |
|
|
34
|
+
if [ "${{ github.ref_type }}" != "tag" ]; then
|
|
35
|
+
echo "Error: Workflow must be triggered with a tag selected. Current ref_type is ${{ github.ref_type }}."
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
TAG_NAME=${{ github.ref_name }}
|
|
39
|
+
echo "Selected tag is $TAG_NAME"
|
|
40
|
+
|
|
41
|
+
- name: Extract version from tag
|
|
42
|
+
id: release
|
|
43
|
+
run: |
|
|
44
|
+
TAG_NAME=${{ github.ref_name }}
|
|
45
|
+
# Validate tag format
|
|
46
|
+
if [[ ! $TAG_NAME =~ ^v[0-9]+\.[0-9]+\.[0-9]+(a[0-9]+|b[0-9]+|rc[0-9]+)?$ ]]; then
|
|
47
|
+
echo "Invalid tag format. Tag must be in the format vX.Y.Z, vX.Y.ZaN, vX.Y.ZbN, or vX.Y.ZrcN."
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
NEW_VERSION=${TAG_NAME#v}
|
|
51
|
+
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
|
52
|
+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
53
|
+
echo "Tag name is $TAG_NAME"
|
|
54
|
+
echo "Version is $NEW_VERSION"
|
|
55
|
+
|
|
56
|
+
setup_build_and_publish:
|
|
57
|
+
name: Build Package and Publish to PyPI
|
|
58
|
+
needs: [get_tag_details]
|
|
59
|
+
runs-on: msgflux-python-runner
|
|
60
|
+
permissions:
|
|
61
|
+
contents: read
|
|
62
|
+
id-token: write # Required for trusted publishing to PyPI
|
|
63
|
+
steps:
|
|
64
|
+
- name: Checkout the repository
|
|
65
|
+
uses: actions/checkout@v4
|
|
66
|
+
with:
|
|
67
|
+
fetch-depth: 0
|
|
68
|
+
|
|
69
|
+
- name: Set up Python
|
|
70
|
+
uses: actions/setup-python@v5
|
|
71
|
+
with:
|
|
72
|
+
python-version: "3.10"
|
|
73
|
+
|
|
74
|
+
- name: Install uv
|
|
75
|
+
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6
|
|
76
|
+
with:
|
|
77
|
+
version: "0.7.3"
|
|
78
|
+
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: uv sync --locked
|
|
81
|
+
|
|
82
|
+
- name: Build source and wheel distribution
|
|
83
|
+
run: |
|
|
84
|
+
uv build
|
|
85
|
+
|
|
86
|
+
- name: Upload build artifacts
|
|
87
|
+
uses: actions/upload-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
name: dist
|
|
90
|
+
path: dist/*
|
|
91
|
+
if-no-files-found: error
|
|
92
|
+
|
|
93
|
+
- name: Publish to PyPI
|
|
94
|
+
run: uv publish
|
|
95
|
+
|
|
96
|
+
github_release:
|
|
97
|
+
name: Create GitHub Release
|
|
98
|
+
needs: [get_tag_details, setup_build_and_publish]
|
|
99
|
+
runs-on: msgflux-python-runner
|
|
100
|
+
permissions:
|
|
101
|
+
contents: write
|
|
102
|
+
steps:
|
|
103
|
+
- name: Checkout Code
|
|
104
|
+
uses: actions/checkout@v4
|
|
105
|
+
with:
|
|
106
|
+
fetch-depth: 0
|
|
107
|
+
|
|
108
|
+
- name: Download build artifacts
|
|
109
|
+
uses: actions/download-artifact@v4
|
|
110
|
+
with:
|
|
111
|
+
name: dist
|
|
112
|
+
path: dist/
|
|
113
|
+
|
|
114
|
+
- name: Create GitHub Release
|
|
115
|
+
id: create_release
|
|
116
|
+
env:
|
|
117
|
+
GH_TOKEN: ${{ github.token }}
|
|
118
|
+
run: |
|
|
119
|
+
gh release create ${{ needs.get_tag_details.outputs.tag_name }} dist/* --title ${{ needs.get_tag_details.outputs.tag_name }} --generate-notes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
env/
|
|
2
|
+
.env
|
|
3
|
+
venv/
|
|
4
|
+
.venv
|
|
5
|
+
.envrc
|
|
6
|
+
env3*/
|
|
7
|
+
Pipfile
|
|
8
|
+
*.lock
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*.egg-info/
|
|
11
|
+
/build/
|
|
12
|
+
dist/
|
|
13
|
+
.cache/
|
|
14
|
+
/site/
|
|
15
|
+
/site.zip
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.python-version
|
|
18
|
+
__pycache__/
|
|
19
|
+
.vscode/
|
|
20
|
+
_build/
|
|
21
|
+
.auto-format
|
|
22
|
+
/sandbox/
|
|
23
|
+
/worktrees/
|
|
24
|
+
/.ruff_cache/
|
|
25
|
+
.DS_Store
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
default_install_hook_types: [pre-commit, pre-push]
|
|
2
|
+
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
5
|
+
rev: v8.23.1
|
|
6
|
+
hooks:
|
|
7
|
+
- id: gitleaks
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
10
|
+
rev: 0.8.3 # uv version.
|
|
11
|
+
hooks:
|
|
12
|
+
- id: uv-lock
|
|
13
|
+
|
|
14
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
15
|
+
rev: v0.11.7
|
|
16
|
+
hooks:
|
|
17
|
+
- id: ruff
|
|
18
|
+
args: [--fix]
|
|
19
|
+
- id: ruff-format
|
msgflux-0.1.0a1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 msgflux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
msgflux-0.1.0a1/PKG-INFO
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: msgflux
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Messages and Dynamic AI Systems in Python powered by pretrained models
|
|
5
|
+
Project-URL: Homepage, https://github.com/msgflux/msgspec-ext
|
|
6
|
+
Project-URL: Documentation, https://github.com/msgflux/msgspec-ext
|
|
7
|
+
Project-URL: Repository, https://github.com/msgflux/msgspec-ext
|
|
8
|
+
Author-email: Vilson Rodrigues <vilson@msgflux.com>
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Requires-Dist: code2mermaid>=0.3.0
|
|
28
|
+
Requires-Dist: jinja2>=3.1.6
|
|
29
|
+
Requires-Dist: mermaid-py>=0.8.0
|
|
30
|
+
Requires-Dist: msgspec-ext>=0.1.0
|
|
31
|
+
Requires-Dist: opentelemetry-api>=1.35.0
|
|
32
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.35.0
|
|
33
|
+
Requires-Dist: opentelemetry-sdk>=1.35.0
|
|
34
|
+
Requires-Dist: tenacity>=9.1.2
|
|
35
|
+
Requires-Dist: tomli-w>=1.2.0
|
|
36
|
+
Requires-Dist: typing-extensions>=4.14.1
|
|
37
|
+
Requires-Dist: uvloop>=0.21.0
|
|
38
|
+
Provides-Extra: httpx
|
|
39
|
+
Requires-Dist: httpx>=0.28.1; extra == 'httpx'
|
|
40
|
+
Provides-Extra: openai
|
|
41
|
+
Requires-Dist: openai>=1.97.1; extra == 'openai'
|
|
42
|
+
Requires-Dist: opentelemetry-instrumentation-openai>=0.43.1; extra == 'openai'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# msgFlux
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# msgFlux
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "msgflux"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "Messages and Dynamic AI Systems in Python powered by pretrained models"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Vilson Rodrigues", email = "vilson@msgflux.com" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.9"
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Information Technology",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: MacOS :: MacOS X",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Operating System :: Microsoft :: Windows",
|
|
24
|
+
"Programming Language :: Python",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Information Analysis"
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"code2mermaid>=0.3.0",
|
|
35
|
+
"jinja2>=3.1.6",
|
|
36
|
+
"mermaid-py>=0.8.0",
|
|
37
|
+
"msgspec-ext>=0.1.0",
|
|
38
|
+
"opentelemetry-api>=1.35.0",
|
|
39
|
+
"opentelemetry-exporter-otlp>=1.35.0",
|
|
40
|
+
"opentelemetry-sdk>=1.35.0",
|
|
41
|
+
"tenacity>=9.1.2",
|
|
42
|
+
"tomli-w>=1.2.0",
|
|
43
|
+
"typing-extensions>=4.14.1",
|
|
44
|
+
"uvloop>=0.21.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.hatch.version]
|
|
48
|
+
path = "src/msgflux/version.py"
|
|
49
|
+
|
|
50
|
+
[dependency-groups]
|
|
51
|
+
dev = [
|
|
52
|
+
"pytest>=8.4.1",
|
|
53
|
+
"pytest-asyncio>=1.1.0",
|
|
54
|
+
"pytest-cov>=6.2.1",
|
|
55
|
+
"ruff>=0.12.5",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://github.com/msgflux/msgspec-ext"
|
|
60
|
+
Documentation = "https://github.com/msgflux/msgspec-ext"
|
|
61
|
+
Repository = "https://github.com/msgflux/msgspec-ext"
|
|
62
|
+
|
|
63
|
+
[project.optional-dependencies]
|
|
64
|
+
openai = [
|
|
65
|
+
"openai>=1.97.1",
|
|
66
|
+
"opentelemetry-instrumentation-openai>=0.43.1",
|
|
67
|
+
]
|
|
68
|
+
httpx = [
|
|
69
|
+
"httpx>=0.28.1",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
target-version = "py39"
|
|
74
|
+
line-length = 88
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = [
|
|
78
|
+
"A",
|
|
79
|
+
"ARG",
|
|
80
|
+
"B",
|
|
81
|
+
"C",
|
|
82
|
+
"D",
|
|
83
|
+
"DTZ",
|
|
84
|
+
"E",
|
|
85
|
+
"EM",
|
|
86
|
+
"F",
|
|
87
|
+
"FBT",
|
|
88
|
+
"I",
|
|
89
|
+
"ICN",
|
|
90
|
+
"ISC",
|
|
91
|
+
"N",
|
|
92
|
+
"PLC",
|
|
93
|
+
"PLE",
|
|
94
|
+
"PLR",
|
|
95
|
+
"PLW",
|
|
96
|
+
"Q",
|
|
97
|
+
"RUF",
|
|
98
|
+
"S",
|
|
99
|
+
"T",
|
|
100
|
+
"TID",
|
|
101
|
+
"UP",
|
|
102
|
+
"W",
|
|
103
|
+
"YTT",
|
|
104
|
+
]
|
|
105
|
+
ignore = [
|
|
106
|
+
"D100", # Allow missing docstring in top level module
|
|
107
|
+
"D104", # Allow missing docstring in public package
|
|
108
|
+
"D105", # Allow missing docstring in magic method
|
|
109
|
+
"D203", # Allow docstring directly below class definition (as enforced by D211)
|
|
110
|
+
"D213", # Allow multi-line-summary on first line of docstring (as enforced by D212)
|
|
111
|
+
"D401", # Allow non imperative mood in docstring
|
|
112
|
+
"D413", # Allow no new line at end of docstring.
|
|
113
|
+
"EM101", # Allow `raise ValueError(msg)`
|
|
114
|
+
"EM102", # Allow f strings in `raise` statements
|
|
115
|
+
"FBT003", # Allow boolean positional values in function calls, like `dict.get(... True)`
|
|
116
|
+
"TID252", # Allow relative imports
|
|
117
|
+
"UP007", # Allow `from typing import Optional` instead of `X | None`
|
|
118
|
+
"UP035", # Allow `from typing import Sequence` instead of `Sequence[X]`
|
|
119
|
+
"PLR0913",
|
|
120
|
+
]
|
|
121
|
+
unfixable = ["F401"]
|
|
122
|
+
|
|
123
|
+
[tool.ruff.lint.isort]
|
|
124
|
+
known-first-party = ["msgflux"]
|
|
125
|
+
|
|
126
|
+
[tool.ruff.lint.flake8-tidy-imports]
|
|
127
|
+
ban-relative-imports = "all"
|
|
128
|
+
|
|
129
|
+
[tool.ruff.lint.per-file-ignores]
|
|
130
|
+
"tests/**/*" = [
|
|
131
|
+
"D",
|
|
132
|
+
"PLR0911",
|
|
133
|
+
"PLR0912",
|
|
134
|
+
"PLR0915",
|
|
135
|
+
"PLR2004",
|
|
136
|
+
"S101",
|
|
137
|
+
"S105",
|
|
138
|
+
"S106",
|
|
139
|
+
"S107",
|
|
140
|
+
"TID252",
|
|
141
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .cache import response_cache
|
|
2
|
+
from .data.databases.database import DataBase
|
|
3
|
+
from .data.retrievers.retriever import Retriever
|
|
4
|
+
from .dotdict import dotdict
|
|
5
|
+
from .dsl.inline import inline
|
|
6
|
+
from .dsl.signature import InputField, OutputField, Signature
|
|
7
|
+
from .envs import set_envs
|
|
8
|
+
from .message import Message
|
|
9
|
+
from .models.gateway import ModelGateway
|
|
10
|
+
from .models.model import Model
|
|
11
|
+
from .utils.chat import ChatML
|
|
12
|
+
from .utils.inspect import get_fn_name
|
|
13
|
+
from .utils.msgspec import load, save
|
|
14
|
+
from .utils.tool import tool_config
|
|
15
|
+
from .telemetry.span import instrument
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"ChatML",
|
|
20
|
+
"DataBase",
|
|
21
|
+
"InputField",
|
|
22
|
+
"Message",
|
|
23
|
+
"Model",
|
|
24
|
+
"ModelGateway",
|
|
25
|
+
"OutputField",
|
|
26
|
+
"Retriever",
|
|
27
|
+
"Signature",
|
|
28
|
+
"dotdict",
|
|
29
|
+
"get_fn_name",
|
|
30
|
+
"inline",
|
|
31
|
+
"instrument",
|
|
32
|
+
"load",
|
|
33
|
+
"response_cache",
|
|
34
|
+
"save",
|
|
35
|
+
"set_envs",
|
|
36
|
+
"tool_config"
|
|
37
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from msgflux._private.core import Core
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseClient(ABC, Core):
|
|
7
|
+
"""
|
|
8
|
+
BaseClient is an abstract base class that defines the interface and common behavior
|
|
9
|
+
for client classes in the msgflux system.
|
|
10
|
+
|
|
11
|
+
This class inherits from `Core` to leverage its state management capabilities and
|
|
12
|
+
extends it with additional functionality specific to clients. It requires subclasses
|
|
13
|
+
to implement certain methods, ensuring a consistent interface across different client
|
|
14
|
+
implementations.
|
|
15
|
+
|
|
16
|
+
Subclasses must implement the `_initialize` and `__call__` methods, which are
|
|
17
|
+
essential for client initialization and operation, respectively. Additionally, this
|
|
18
|
+
class provides methods for serialization and deserialization, allowing client instances
|
|
19
|
+
to be easily saved and restored.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
to_ignore ([optional[list[str]]): A list of attribute keys to be ignored during serialization.
|
|
23
|
+
msgflux_type (str): A string identifying the type of the client in the msgflux system.
|
|
24
|
+
provider (optional[str]): The provider associated with the client, if applicable.
|
|
25
|
+
instance_type (optional[callable]): A method or callable that returns additional
|
|
26
|
+
instance-specific data to be included during serialization.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def __call__(self):
|
|
31
|
+
"""
|
|
32
|
+
Execute the client's main functionality. This method must be implemented by subclasses.
|
|
33
|
+
|
|
34
|
+
This method defines the primary behavior of the client and is called when the instance
|
|
35
|
+
is invoked as a function.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
NotImplementedError: If the method is not implemented by the subclass.
|
|
39
|
+
"""
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
|
|
42
|
+
async def acall(self, *args, **kwargs):
|
|
43
|
+
""" Async interface to __call__ """
|
|
44
|
+
return self.__call__(*args, **kwargs)
|
|
45
|
+
|
|
46
|
+
def serialize(self) -> Dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Serialize the client instance into a dictionary.
|
|
49
|
+
|
|
50
|
+
This method prepares the client's state for serialization by removing unnecessary
|
|
51
|
+
attributes and including additional metadata such as the client type and provider.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Dict[str, Any]: A dictionary containing the serialized state of the client,
|
|
55
|
+
including metadata and the client's internal state.
|
|
56
|
+
"""
|
|
57
|
+
state = self.__getstate__()
|
|
58
|
+
if hasattr(self, "to_ignore"):
|
|
59
|
+
for key in self.to_ignore:
|
|
60
|
+
state.pop(key, None)
|
|
61
|
+
data = {"msgflux_type": self.msgflux_type}
|
|
62
|
+
if hasattr(self, "provider"):
|
|
63
|
+
data["provider"] = self.provider
|
|
64
|
+
if hasattr(self, "instance_type"):
|
|
65
|
+
instance_type = self.instance_type()
|
|
66
|
+
data.update(instance_type)
|
|
67
|
+
data["state"] = state
|
|
68
|
+
return data
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def from_serialized(cls, state: Dict[str, Any]):
|
|
72
|
+
"""
|
|
73
|
+
Deserialize a client instance from a dictionary.
|
|
74
|
+
|
|
75
|
+
This method creates a new instance of the client and restores its state from the
|
|
76
|
+
provided dictionary. It also ensures that the client is properly initialized
|
|
77
|
+
after deserialization.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
state (Dict[str, Any]): A dictionary containing the serialized state of the client.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
BaseClient: A new instance of the client with its state restored.
|
|
84
|
+
"""
|
|
85
|
+
if "msgflux_type" in state:
|
|
86
|
+
state.pop("msgflux_type")
|
|
87
|
+
instance = cls()
|
|
88
|
+
instance.__setstate__(state)
|
|
89
|
+
if hasattr(instance, "_initialize"):
|
|
90
|
+
instance._initialize()
|
|
91
|
+
return instance
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class Core:
|
|
2
|
+
"""
|
|
3
|
+
Core is a set of methods that are common among some classes in msgflux.
|
|
4
|
+
|
|
5
|
+
This class provides basic functionality for state management, allowing instances
|
|
6
|
+
to be serialized and deserialized. It is intended to be inherited by other classes
|
|
7
|
+
that require these common features.
|
|
8
|
+
"""
|
|
9
|
+
def __getstate__(self):
|
|
10
|
+
state = self.__dict__.copy()
|
|
11
|
+
return state
|
|
12
|
+
|
|
13
|
+
def __setstate__(self, state):
|
|
14
|
+
self.__dict__.update(state)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import threading
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
4
|
+
from typing import Callable
|
|
5
|
+
import uvloop
|
|
6
|
+
from msgflux.envs import envs
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncWorker:
|
|
10
|
+
def __init__(self):
|
|
11
|
+
"""Initializes a worker with its own event loop in a separate thread."""
|
|
12
|
+
self.loop = uvloop.new_event_loop()
|
|
13
|
+
self.thread = threading.Thread(target=self.loop.run_forever)
|
|
14
|
+
self.thread.start()
|
|
15
|
+
|
|
16
|
+
def submit(self, coro):
|
|
17
|
+
"""Submits a coroutine to the worker's event loop."""
|
|
18
|
+
return asyncio.run_coroutine_threadsafe(coro, self.loop)
|
|
19
|
+
|
|
20
|
+
def shutdown(self):
|
|
21
|
+
"""Terminates the event loop and worker thread."""
|
|
22
|
+
self.loop.call_soon_threadsafe(self.loop.stop)
|
|
23
|
+
self.thread.join()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Executor:
|
|
27
|
+
"""
|
|
28
|
+
Async pool to manage the execution of synchronous and asynchronous code.
|
|
29
|
+
Executor distributes tasks among a ThreadPool or among Async Workers.
|
|
30
|
+
"""
|
|
31
|
+
_instance = None
|
|
32
|
+
_lock = threading.Lock()
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.num_threads = envs.executor_num_threads
|
|
36
|
+
self.num_async_workers = envs.executor_num_async_workers
|
|
37
|
+
self.async_worker_index = 0
|
|
38
|
+
self.thread_pool = ThreadPoolExecutor(max_workers=self.num_threads)
|
|
39
|
+
self.async_workers = [AsyncWorker() for _ in range(self.num_async_workers)]
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_instance(cls):
|
|
43
|
+
"""Returns the singleton instance in a thread-safe manner."""
|
|
44
|
+
if cls._instance is None:
|
|
45
|
+
with cls._lock:
|
|
46
|
+
if cls._instance is None:
|
|
47
|
+
cls._instance = cls()
|
|
48
|
+
return cls._instance
|
|
49
|
+
|
|
50
|
+
def submit(self, f: Callable, *args, **kwargs):
|
|
51
|
+
"""
|
|
52
|
+
Submits a task to the appropriate pool based on the function type.
|
|
53
|
+
Returns a Future to track the result.
|
|
54
|
+
"""
|
|
55
|
+
if hasattr(f, "acall"):
|
|
56
|
+
coro = f.acall(*args, **kwargs)
|
|
57
|
+
return self._submit_to_async_worker(coro)
|
|
58
|
+
elif asyncio.iscoroutinefunction(f):
|
|
59
|
+
coro = f(*args, **kwargs)
|
|
60
|
+
return self._submit_to_async_worker(coro)
|
|
61
|
+
else:
|
|
62
|
+
return self.thread_pool.submit(f, *args, **kwargs)
|
|
63
|
+
|
|
64
|
+
def _submit_to_async_worker(self, coro):
|
|
65
|
+
"""Distribute a coroutine to an asynchronous worker using round-robin."""
|
|
66
|
+
worker = self.async_workers[self.async_worker_index]
|
|
67
|
+
self.async_worker_index = (self.async_worker_index + 1) % self.num_async_workers
|
|
68
|
+
return worker.submit(coro)
|
|
69
|
+
|
|
70
|
+
def shutdown(self):
|
|
71
|
+
"""Shutdown the executor, closing the pools."""
|
|
72
|
+
self.thread_pool.shutdown()
|
|
73
|
+
for worker in self.async_workers:
|
|
74
|
+
worker.shutdown()
|
|
75
|
+
|
|
76
|
+
def __del__(self):
|
|
77
|
+
self.shutdown()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from msgflux.data.databases.base import BaseDB
|
|
4
|
+
from msgflux.message import Message
|
|
5
|
+
from msgflux.models.types import TextEmbedderModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def response_cache(
|
|
9
|
+
db: BaseDB,
|
|
10
|
+
task_inputs: Optional[str] = None,
|
|
11
|
+
response_mode: Optional[str] = None,
|
|
12
|
+
model: Optional[TextEmbedderModel] = None,
|
|
13
|
+
):
|
|
14
|
+
def decorator(func):
|
|
15
|
+
@wraps(func)
|
|
16
|
+
def wrapper(msg):
|
|
17
|
+
if isinstance(msg, Message):
|
|
18
|
+
if task_inputs is None:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
"`task_inputs` is required when input "
|
|
21
|
+
"is a Message instance"
|
|
22
|
+
)
|
|
23
|
+
key = msg.get(task_inputs)
|
|
24
|
+
else:
|
|
25
|
+
key = msg
|
|
26
|
+
|
|
27
|
+
if model:
|
|
28
|
+
key = model(key)
|
|
29
|
+
|
|
30
|
+
cached_response = db(key)
|
|
31
|
+
|
|
32
|
+
if cached_response is not None:
|
|
33
|
+
if isinstance(msg, Message):
|
|
34
|
+
if response_mode is None:
|
|
35
|
+
raise ValueError(
|
|
36
|
+
"`response_mode` is required when "
|
|
37
|
+
"input is a Message instance"
|
|
38
|
+
)
|
|
39
|
+
msg.set(response_mode, cached_response)
|
|
40
|
+
return msg
|
|
41
|
+
return cached_response
|
|
42
|
+
|
|
43
|
+
response = func(msg)
|
|
44
|
+
|
|
45
|
+
if response is not None:
|
|
46
|
+
db.add(key, response)
|
|
47
|
+
|
|
48
|
+
return response
|
|
49
|
+
return wrapper
|
|
50
|
+
return decorator
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#https://github.com/openai/openai-python/blob/384e6b23ce0366d6b2f31cc98d35525da5b22c10/src/openai/helpers/local_audio_player.py#L19
|
|
File without changes
|