hiyal 0.0.1__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.
Files changed (126) hide show
  1. hiyal-0.0.1/.github/dependabot.yml +9 -0
  2. hiyal-0.0.1/.github/scripts/check_version.py +29 -0
  3. hiyal-0.0.1/.github/workflows/ci.yml +120 -0
  4. hiyal-0.0.1/.github/workflows/release.yml +109 -0
  5. hiyal-0.0.1/.gitignore +22 -0
  6. hiyal-0.0.1/.python-version +1 -0
  7. hiyal-0.0.1/LICENSE +21 -0
  8. hiyal-0.0.1/PKG-INFO +39 -0
  9. hiyal-0.0.1/README.md +11 -0
  10. hiyal-0.0.1/docs/assets/logo.png +0 -0
  11. hiyal-0.0.1/pyproject.toml +51 -0
  12. hiyal-0.0.1/src/hiyal/__init__.py +1 -0
  13. hiyal-0.0.1/src/hiyal/models/__init__.py +20 -0
  14. hiyal-0.0.1/src/hiyal/models/anthropic/__init__.py +11 -0
  15. hiyal-0.0.1/src/hiyal/models/anthropic/llm.py +23 -0
  16. hiyal-0.0.1/src/hiyal/models/anthropic/thinking.py +63 -0
  17. hiyal-0.0.1/src/hiyal/models/anthropic/translator.py +379 -0
  18. hiyal-0.0.1/src/hiyal/models/anthropic/transport.py +40 -0
  19. hiyal-0.0.1/src/hiyal/models/bases/__init__.py +20 -0
  20. hiyal-0.0.1/src/hiyal/models/bases/async_llm_stream.py +94 -0
  21. hiyal-0.0.1/src/hiyal/models/bases/base_llm.py +223 -0
  22. hiyal-0.0.1/src/hiyal/models/bases/config_resolver.py +160 -0
  23. hiyal-0.0.1/src/hiyal/models/bases/llm_stream.py +89 -0
  24. hiyal-0.0.1/src/hiyal/models/bases/stream_accumulator.py +119 -0
  25. hiyal-0.0.1/src/hiyal/models/bases/translator.py +312 -0
  26. hiyal-0.0.1/src/hiyal/models/bases/transport.py +172 -0
  27. hiyal-0.0.1/src/hiyal/models/bases/types.py +6 -0
  28. hiyal-0.0.1/src/hiyal/models/deepseek/__init__.py +5 -0
  29. hiyal-0.0.1/src/hiyal/models/deepseek/llm.py +23 -0
  30. hiyal-0.0.1/src/hiyal/models/deepseek/translator.py +46 -0
  31. hiyal-0.0.1/src/hiyal/models/deepseek/transport.py +26 -0
  32. hiyal-0.0.1/src/hiyal/models/gemini/__init__.py +12 -0
  33. hiyal-0.0.1/src/hiyal/models/gemini/llm.py +21 -0
  34. hiyal-0.0.1/src/hiyal/models/gemini/thinking.py +82 -0
  35. hiyal-0.0.1/src/hiyal/models/gemini/translator.py +474 -0
  36. hiyal-0.0.1/src/hiyal/models/gemini/transport.py +155 -0
  37. hiyal-0.0.1/src/hiyal/models/llm.py +46 -0
  38. hiyal-0.0.1/src/hiyal/models/ollama/__init__.py +11 -0
  39. hiyal-0.0.1/src/hiyal/models/ollama/llm.py +25 -0
  40. hiyal-0.0.1/src/hiyal/models/ollama/request.py +110 -0
  41. hiyal-0.0.1/src/hiyal/models/ollama/thinking.py +65 -0
  42. hiyal-0.0.1/src/hiyal/models/ollama/translator.py +383 -0
  43. hiyal-0.0.1/src/hiyal/models/ollama/transport.py +105 -0
  44. hiyal-0.0.1/src/hiyal/models/openai/__init__.py +16 -0
  45. hiyal-0.0.1/src/hiyal/models/openai/chat_contents.py +216 -0
  46. hiyal-0.0.1/src/hiyal/models/openai/chat_translator.py +215 -0
  47. hiyal-0.0.1/src/hiyal/models/openai/llm.py +21 -0
  48. hiyal-0.0.1/src/hiyal/models/openai/translator.py +509 -0
  49. hiyal-0.0.1/src/hiyal/models/openai/transport.py +69 -0
  50. hiyal-0.0.1/src/hiyal/models/schemas/__init__.py +41 -0
  51. hiyal-0.0.1/src/hiyal/models/schemas/config.py +232 -0
  52. hiyal-0.0.1/src/hiyal/models/schemas/fields.py +39 -0
  53. hiyal-0.0.1/src/hiyal/models/schemas/response.py +208 -0
  54. hiyal-0.0.1/src/hiyal/models/schemas/stream.py +119 -0
  55. hiyal-0.0.1/src/hiyal/models/schemas/thinking.py +82 -0
  56. hiyal-0.0.1/src/hiyal/models/schemas/types.py +57 -0
  57. hiyal-0.0.1/src/hiyal/models/schemas/usage.py +79 -0
  58. hiyal-0.0.1/src/hiyal/prompts/__init__.py +4 -0
  59. hiyal-0.0.1/src/hiyal/prompts/media.py +250 -0
  60. hiyal-0.0.1/src/hiyal/prompts/messages.py +50 -0
  61. hiyal-0.0.1/src/hiyal/tools/__init__.py +14 -0
  62. hiyal-0.0.1/src/hiyal/tools/calls/__init__.py +0 -0
  63. hiyal-0.0.1/src/hiyal/tools/calls/anthropic.py +86 -0
  64. hiyal-0.0.1/src/hiyal/tools/calls/gemini.py +46 -0
  65. hiyal-0.0.1/src/hiyal/tools/calls/ollama.py +30 -0
  66. hiyal-0.0.1/src/hiyal/tools/calls/openai.py +106 -0
  67. hiyal-0.0.1/src/hiyal/tools/calls/responses.py +218 -0
  68. hiyal-0.0.1/src/hiyal/tools/calls/spec.py +456 -0
  69. hiyal-0.0.1/src/hiyal/tools/decorator.py +78 -0
  70. hiyal-0.0.1/src/hiyal/tools/introspection.py +275 -0
  71. hiyal-0.0.1/src/hiyal/utility/__init__.py +6 -0
  72. hiyal-0.0.1/src/hiyal/utility/dicts.py +31 -0
  73. hiyal-0.0.1/src/hiyal/utility/identifiers.py +10 -0
  74. hiyal-0.0.1/src/hiyal/utility/parsing.py +19 -0
  75. hiyal-0.0.1/src/hiyal/utility/timing.py +20 -0
  76. hiyal-0.0.1/tests/__init__.py +0 -0
  77. hiyal-0.0.1/tests/conftest.py +19 -0
  78. hiyal-0.0.1/tests/legacy/test_connection_overrides.py +519 -0
  79. hiyal-0.0.1/tests/legacy/test_gemini.py +304 -0
  80. hiyal-0.0.1/tests/legacy/test_llm_config.py +140 -0
  81. hiyal-0.0.1/tests/legacy/test_llm_factory.py +114 -0
  82. hiyal-0.0.1/tests/legacy/test_media.py +281 -0
  83. hiyal-0.0.1/tests/legacy/test_model_config.py +404 -0
  84. hiyal-0.0.1/tests/legacy/test_openai_tools.py +331 -0
  85. hiyal-0.0.1/tests/legacy/test_provider_tools.py +429 -0
  86. hiyal-0.0.1/tests/legacy/test_public_imports.py +28 -0
  87. hiyal-0.0.1/tests/legacy/test_thinking.py +394 -0
  88. hiyal-0.0.1/tests/legacy/test_tool_call.py +129 -0
  89. hiyal-0.0.1/tests/legacy/test_tool_decorator.py +628 -0
  90. hiyal-0.0.1/tests/legacy/test_tools_shorthand.py +109 -0
  91. hiyal-0.0.1/tests/models/__init__.py +0 -0
  92. hiyal-0.0.1/tests/models/anthropic/__init__.py +0 -0
  93. hiyal-0.0.1/tests/models/anthropic/test_anthropic.py +390 -0
  94. hiyal-0.0.1/tests/models/bases/__init__.py +0 -0
  95. hiyal-0.0.1/tests/models/bases/fakes.py +130 -0
  96. hiyal-0.0.1/tests/models/bases/test_base_llm.py +237 -0
  97. hiyal-0.0.1/tests/models/bases/test_config_resolver.py +222 -0
  98. hiyal-0.0.1/tests/models/bases/test_translator_base.py +212 -0
  99. hiyal-0.0.1/tests/models/bases/test_transport_and_streams.py +276 -0
  100. hiyal-0.0.1/tests/models/deepseek/__init__.py +0 -0
  101. hiyal-0.0.1/tests/models/deepseek/test_deepseek.py +175 -0
  102. hiyal-0.0.1/tests/models/gemini/__init__.py +0 -0
  103. hiyal-0.0.1/tests/models/gemini/test_gemini_translator.py +349 -0
  104. hiyal-0.0.1/tests/models/gemini/test_gemini_transport.py +203 -0
  105. hiyal-0.0.1/tests/models/ollama/__init__.py +0 -0
  106. hiyal-0.0.1/tests/models/ollama/test_ollama.py +476 -0
  107. hiyal-0.0.1/tests/models/openai/__init__.py +0 -0
  108. hiyal-0.0.1/tests/models/openai/test_chat_completions.py +219 -0
  109. hiyal-0.0.1/tests/models/openai/test_openai_e2e.py +244 -0
  110. hiyal-0.0.1/tests/models/openai/test_openai_translator.py +321 -0
  111. hiyal-0.0.1/tests/models/schemas/__init__.py +0 -0
  112. hiyal-0.0.1/tests/models/schemas/test_config.py +186 -0
  113. hiyal-0.0.1/tests/models/schemas/test_schemas.py +216 -0
  114. hiyal-0.0.1/tests/models/test_llm_factory_and_exports.py +77 -0
  115. hiyal-0.0.1/tests/prompts/__init__.py +0 -0
  116. hiyal-0.0.1/tests/prompts/test_media.py +315 -0
  117. hiyal-0.0.1/tests/prompts/test_messages.py +70 -0
  118. hiyal-0.0.1/tests/support.py +221 -0
  119. hiyal-0.0.1/tests/tools/__init__.py +0 -0
  120. hiyal-0.0.1/tests/tools/test_introspection_and_decorator.py +632 -0
  121. hiyal-0.0.1/tests/tools/test_specs.py +356 -0
  122. hiyal-0.0.1/tests/tools/test_tool_call_model.py +129 -0
  123. hiyal-0.0.1/tests/tools/test_tool_call_normalize.py +137 -0
  124. hiyal-0.0.1/tests/typing/tool_examples.py +45 -0
  125. hiyal-0.0.1/tests/utility/__init__.py +0 -0
  126. hiyal-0.0.1/tests/utility/test_utility.py +106 -0
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ # Keep the workflow actions current.
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
8
+ commit-message:
9
+ prefix: "ci"
@@ -0,0 +1,29 @@
1
+ """Fail unless every place that states the version agrees.
2
+
3
+ The version lives in pyproject.toml and in ``hiyal.__version__``. When a tag
4
+ name is passed (``python check_version.py v0.1.0``), it must match too.
5
+ """
6
+
7
+ import re
8
+ import sys
9
+ import tomllib
10
+ from pathlib import Path
11
+
12
+ root = Path(__file__).resolve().parents[2]
13
+ project = tomllib.loads((root / "pyproject.toml").read_text())["project"]["version"]
14
+ match = re.search(
15
+ r'^__version__\s*=\s*["\']([^"\']+)["\']',
16
+ (root / "src/hiyal/__init__.py").read_text(),
17
+ re.MULTILINE,
18
+ )
19
+ package = match.group(1) if match else None
20
+
21
+ versions = {"pyproject.toml": project, "hiyal.__version__": package}
22
+ if len(sys.argv) > 1:
23
+ versions["git tag"] = sys.argv[1].removeprefix("v")
24
+
25
+ for source, value in versions.items():
26
+ print(f"{source:20} {value}")
27
+ if len(set(versions.values())) != 1:
28
+ sys.exit("error: the versions above disagree")
29
+ print("versions agree")
@@ -0,0 +1,120 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ # The release workflow runs the whole suite before publishing.
9
+ workflow_call:
10
+ # Weekly run: the SDKs are only lower-bounded, so a new release of
11
+ # openai/anthropic/google-genai/ollama can break us without a commit.
12
+ schedule:
13
+ - cron: "17 5 * * 1"
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ concurrency:
19
+ group: ci-${{ github.workflow }}-${{ github.ref }}
20
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
21
+
22
+ jobs:
23
+ lint:
24
+ name: Lint
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v7
28
+ with:
29
+ persist-credentials: false
30
+ - uses: astral-sh/setup-uv@v10.3.3
31
+ # Pinned: ruff changes its default rules between releases. Bump on purpose.
32
+ - run: uvx ruff@0.17.4 check .
33
+
34
+ test:
35
+ name: Test (Python ${{ matrix.python }}, ${{ matrix.resolution }} dependencies)
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python: ["3.12", "3.13"]
41
+ resolution: [highest]
42
+ include:
43
+ # The oldest versions pyproject.toml allows must really work.
44
+ - python: "3.12"
45
+ resolution: lowest-direct
46
+ steps:
47
+ - uses: actions/checkout@v7
48
+ with:
49
+ persist-credentials: false
50
+ - uses: astral-sh/setup-uv@v10.3.3
51
+ - name: Run the tests
52
+ run: uv run --isolated --python ${{ matrix.python }} --resolution ${{ matrix.resolution }} pytest -ra
53
+
54
+ coverage:
55
+ name: Coverage
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v7
59
+ with:
60
+ persist-credentials: false
61
+ - uses: astral-sh/setup-uv@v10.3.3
62
+ - name: Run the tests with coverage
63
+ run: >
64
+ uv run --isolated --python 3.12 --with pytest-cov
65
+ pytest --cov=hiyal --cov-branch --cov-report=term-missing:skip-covered
66
+ --cov-report=xml --cov-fail-under=95
67
+ - uses: actions/upload-artifact@v7
68
+ with:
69
+ name: coverage-report
70
+ path: coverage.xml
71
+
72
+ build:
73
+ name: Build and check the package
74
+ runs-on: ubuntu-latest
75
+ steps:
76
+ - uses: actions/checkout@v7
77
+ with:
78
+ persist-credentials: false
79
+ - uses: astral-sh/setup-uv@v10.3.3
80
+ - name: Versions agree
81
+ run: uv run --no-project --python 3.12 python .github/scripts/check_version.py
82
+ - name: Build the sdist and wheel
83
+ run: uv build
84
+ - name: Check the metadata
85
+ run: uvx twine check dist/*
86
+ - name: Install the wheel in a clean environment and import it
87
+ run: |
88
+ uv venv "$RUNNER_TEMP/smoke" --python 3.12
89
+ uv pip install --python "$RUNNER_TEMP/smoke/bin/python" dist/*.whl
90
+ cd "$RUNNER_TEMP"
91
+ "$RUNNER_TEMP/smoke/bin/python" -c "
92
+ import hiyal
93
+ from hiyal.models import LLM, AnthropicLLM, DeepSeekLLM, GeminiLLM, OllamaLLM, OpenAILLM
94
+ from hiyal.prompts import UserPrompt
95
+ from hiyal.tools import tool
96
+ from hiyal.models.openai import ChatCompletionsTranslator
97
+ print('hiyal', hiyal.__version__, 'imports OK')
98
+ "
99
+ - uses: actions/upload-artifact@v7
100
+ with:
101
+ # Not "dist": release.yml calls this workflow and uploads its own "dist"
102
+ # in the same run, and artifact names must be unique within a run.
103
+ name: dist-ci
104
+ path: dist/
105
+ if-no-files-found: error
106
+
107
+ # One stable name for branch protection: require "CI passed" and nothing else.
108
+ ci-passed:
109
+ name: CI passed
110
+ if: always()
111
+ needs: [lint, test, coverage, build]
112
+ runs-on: ubuntu-latest
113
+ steps:
114
+ - name: Fail if any job failed or was cancelled
115
+ env:
116
+ BAD: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
117
+ RESULTS: ${{ join(needs.*.result, ' ') }}
118
+ run: |
119
+ echo "job results: $RESULTS"
120
+ test "$BAD" = "false"
@@ -0,0 +1,109 @@
1
+ name: Release
2
+
3
+ # Publishing a release:
4
+ # 1. Bump the version in pyproject.toml and src/hiyal/__init__.py, merge to master.
5
+ # 2. git tag v<version> && git push origin v<version>
6
+ # That runs the full test suite, builds the package, publishes it to PyPI
7
+ # (after approval of the "pypi" environment) and creates the GitHub release.
8
+ #
9
+ # To rehearse on TestPyPI without a tag, run this workflow by hand from the
10
+ # Actions tab; it publishes the current master to TestPyPI only.
11
+
12
+ on:
13
+ push:
14
+ tags: ["v[0-9]+.[0-9]+.[0-9]+*"]
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ concurrency:
21
+ group: release-${{ github.ref }}
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ ci:
26
+ name: Tests
27
+ uses: ./.github/workflows/ci.yml
28
+
29
+ build:
30
+ name: Build distributions
31
+ needs: ci
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v7
35
+ with:
36
+ persist-credentials: false
37
+ - uses: astral-sh/setup-uv@v10.3.3
38
+ - name: The tag, pyproject.toml and hiyal.__version__ agree
39
+ if: github.ref_type == 'tag'
40
+ run: uv run --no-project --python 3.12 python .github/scripts/check_version.py "$GITHUB_REF_NAME"
41
+ - name: The versions agree
42
+ if: github.ref_type != 'tag'
43
+ run: uv run --no-project --python 3.12 python .github/scripts/check_version.py
44
+ - run: uv build
45
+ - run: uvx twine check dist/*
46
+ - uses: actions/upload-artifact@v7
47
+ with:
48
+ name: dist
49
+ path: dist/
50
+ if-no-files-found: error
51
+
52
+ publish-pypi:
53
+ name: Publish to PyPI
54
+ if: github.ref_type == 'tag'
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ environment:
58
+ name: pypi
59
+ url: https://pypi.org/project/hiyal/
60
+ permissions:
61
+ id-token: write # trusted publishing: no API token is stored anywhere
62
+ steps:
63
+ - uses: actions/download-artifact@v8
64
+ with:
65
+ name: dist
66
+ path: dist/
67
+ - uses: pypa/gh-action-pypi-publish@release/v1
68
+
69
+ github-release:
70
+ name: Create the GitHub release
71
+ needs: publish-pypi
72
+ runs-on: ubuntu-latest
73
+ permissions:
74
+ contents: write
75
+ steps:
76
+ - uses: actions/download-artifact@v8
77
+ with:
78
+ name: dist
79
+ path: dist/
80
+ - name: Create the release
81
+ env:
82
+ GH_TOKEN: ${{ github.token }}
83
+ TAG: ${{ github.ref_name }}
84
+ run: |
85
+ # 0.1.0a1, 0.1.0rc1, 0.1.0.dev1 ... are pre-releases.
86
+ flags=""
87
+ if ! [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then flags="--prerelease"; fi
88
+ gh release create "$TAG" dist/* --repo "$GITHUB_REPOSITORY" \
89
+ --title "$TAG" --generate-notes --verify-tag $flags
90
+
91
+ publish-testpypi:
92
+ name: Publish to TestPyPI
93
+ if: github.event_name == 'workflow_dispatch'
94
+ needs: build
95
+ runs-on: ubuntu-latest
96
+ environment:
97
+ name: testpypi
98
+ url: https://test.pypi.org/project/hiyal/
99
+ permissions:
100
+ id-token: write
101
+ steps:
102
+ - uses: actions/download-artifact@v8
103
+ with:
104
+ name: dist
105
+ path: dist/
106
+ - uses: pypa/gh-action-pypi-publish@release/v1
107
+ with:
108
+ repository-url: https://test.pypi.org/legacy/
109
+ skip-existing: true
hiyal-0.0.1/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ uv.lock
12
+ .env
13
+ # Files written by the multimodal notebooks
14
+ multimodal/outputs/
15
+
16
+ private/
17
+ # Test and tool output
18
+ .coverage
19
+ coverage.xml
20
+ htmlcov/
21
+ .pytest_cache/
22
+ .ruff_cache/
@@ -0,0 +1 @@
1
+ 3.12
hiyal-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Okan Yenigün
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.
hiyal-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.5
2
+ Name: hiyal
3
+ Version: 0.0.1
4
+ Summary: Hiyal is an agentic tool. Currently it provides the LLM call component.
5
+ Project-URL: Homepage, https://github.com/okanyenigun/hiyal
6
+ Project-URL: Repository, https://github.com/okanyenigun/hiyal
7
+ Project-URL: Issues, https://github.com/okanyenigun/hiyal/issues
8
+ Author: Okan Yenigün
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai,anthropic,deepseek,gemini,llm,ollama,openai,streaming,tool-calling
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: anthropic>=1.9.0
21
+ Requires-Dist: docstring-parser>=0.18.0
22
+ Requires-Dist: google-genai>=2.25.0
23
+ Requires-Dist: ollama>=0.6.2
24
+ Requires-Dist: openai>=3.22.1
25
+ Requires-Dist: pydantic>=2.12
26
+ Requires-Dist: python-dotenv>=1.2.3
27
+ Description-Content-Type: text/markdown
28
+
29
+ <p align="center">
30
+ <img src="https://raw.githubusercontent.com/okanyenigun/hiyal/master/docs/assets/logo.png" alt="Hiyal" width="160">
31
+ </p>
32
+
33
+ # Hiyal
34
+
35
+ Hiyal is an agentic tool. Right now it has only the LLM call component.
36
+
37
+ ## License
38
+
39
+ [MIT](LICENSE) © Okan Yenigün
hiyal-0.0.1/README.md ADDED
@@ -0,0 +1,11 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/okanyenigun/hiyal/master/docs/assets/logo.png" alt="Hiyal" width="160">
3
+ </p>
4
+
5
+ # Hiyal
6
+
7
+ Hiyal is an agentic tool. Right now it has only the LLM call component.
8
+
9
+ ## License
10
+
11
+ [MIT](LICENSE) © Okan Yenigün
Binary file
@@ -0,0 +1,51 @@
1
+ [project]
2
+ name = "hiyal"
3
+ version = "0.0.1"
4
+ description = "Hiyal is an agentic tool. Currently it provides the LLM call component."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Okan Yenigün" }]
10
+ keywords = ["llm", "openai", "anthropic", "gemini", "ollama", "deepseek", "ai", "tool-calling", "streaming"]
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
19
+ ]
20
+ dependencies = [
21
+ "anthropic>=1.9.0",
22
+ "docstring-parser>=0.18.0",
23
+ "google-genai>=2.25.0",
24
+ "ollama>=0.6.2",
25
+ "openai>=3.22.1",
26
+ "pydantic>=2.12",
27
+ "python-dotenv>=1.2.3",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/okanyenigun/hiyal"
32
+ Repository = "https://github.com/okanyenigun/hiyal"
33
+ Issues = "https://github.com/okanyenigun/hiyal/issues"
34
+
35
+ [build-system]
36
+ requires = ["hatchling"]
37
+ build-backend = "hatchling.build"
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["src/hiyal"]
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "ipykernel>=7.4.0",
45
+ "pytest>=9.2.0",
46
+ ]
47
+
48
+ [tool.ruff.lint]
49
+ # Only real errors: syntax errors, undefined names, unused imports and variables.
50
+ # Style rules (import order, modernisation, ...) are deliberately not enforced.
51
+ select = ["E4", "E7", "E9", "F"]
@@ -0,0 +1 @@
1
+ __version__ = "0.0.1"
@@ -0,0 +1,20 @@
1
+ from .anthropic import AnthropicLLM
2
+ from .bases import BaseLLM
3
+ from .deepseek import DeepSeekLLM
4
+ from .gemini import GeminiLLM
5
+ from .llm import LLM
6
+ from .ollama import OllamaLLM
7
+ from .openai import OpenAILLM
8
+ from .schemas import LLMConfig, ThinkingConfig
9
+
10
+ __all__ = [
11
+ "AnthropicLLM",
12
+ "BaseLLM",
13
+ "DeepSeekLLM",
14
+ "GeminiLLM",
15
+ "LLM",
16
+ "LLMConfig",
17
+ "OllamaLLM",
18
+ "OpenAILLM",
19
+ "ThinkingConfig",
20
+ ]
@@ -0,0 +1,11 @@
1
+ from .llm import AnthropicLLM
2
+ from .translator import AnthropicStreamAccumulator, AnthropicTranslator
3
+ from .transport import AnthropicFileStore, AnthropicTransport
4
+
5
+ __all__ = [
6
+ "AnthropicFileStore",
7
+ "AnthropicLLM",
8
+ "AnthropicStreamAccumulator",
9
+ "AnthropicTranslator",
10
+ "AnthropicTransport",
11
+ ]
@@ -0,0 +1,23 @@
1
+ from .translator import AnthropicTranslator
2
+ from .transport import AnthropicTransport
3
+ from ..bases import BaseLLM
4
+
5
+
6
+ class AnthropicLLM(BaseLLM):
7
+ """Claude models via the Anthropic Messages API."""
8
+
9
+ provider = "anthropic"
10
+ display_name = "Anthropic"
11
+ # Claude reads images and documents; it has no audio input.
12
+ prompt_media = frozenset({"images", "documents"})
13
+ generation_adapter = {
14
+ "messages": "user_prompt",
15
+ "system": "system_prompt",
16
+ "max_tokens": "max_output_tokens",
17
+ }
18
+
19
+ def _create_translator(self) -> AnthropicTranslator:
20
+ return AnthropicTranslator(self.info)
21
+
22
+ def _create_transport(self) -> AnthropicTransport:
23
+ return AnthropicTransport(config=self.config, info=self.info)
@@ -0,0 +1,63 @@
1
+ """Claude thinking controls: ``thinking={"type": ...}`` plus ``output_config.effort``."""
2
+
3
+ import re
4
+ from typing import Any
5
+
6
+ from ...utility import Dicts
7
+ from ..schemas import ThinkingConfig, UnsupportedThinkingError
8
+
9
+ _VERSION = re.compile(r"claude-(?:opus|sonnet|haiku)-(\d+)(?:-(\d+))?")
10
+ # Models whose thinking cannot be switched off.
11
+ _ALWAYS_THINKING = ("claude-fable-", "claude-mythos-", "claude-opus-5-5", "claude-sonnet-5-5")
12
+
13
+
14
+ def apply_claude_thinking(params: dict[str, Any], thinking: ThinkingConfig, model: str) -> None:
15
+ options = {**Dicts.get(params, "thinking", copy=True), **thinking.others}
16
+ output = Dicts.get(params, "output_config", copy=True)
17
+ mode = thinking.mode
18
+ if thinking.budget is not None and mode != "disabled":
19
+ options["budget_tokens"] = thinking.budget
20
+ mode = mode or "enabled"
21
+ version = _VERSION.search(model)
22
+ number = None if version is None else tuple(int(n or 0) for n in version.groups())
23
+ # Before 4.6 only manual budgets exist; from 4.7 only adaptive thinking.
24
+ legacy = number is not None and number < (4, 6)
25
+ manual_unsupported = number is not None and number >= (4, 7)
26
+ if mode == "disabled":
27
+ if model.startswith(_ALWAYS_THINKING):
28
+ raise UnsupportedThinkingError("Claude", model, "thinking cannot be fully disabled; use a supported native mode explicitly")
29
+ options = {key: value for key, value in options.items() if key != "budget_tokens"}
30
+ options["type"] = "disabled"
31
+ output.pop("effort", None)
32
+ else:
33
+ if thinking.effort is not None:
34
+ output["effort"] = thinking.effort
35
+ if mode == "enabled":
36
+ if legacy or "budget_tokens" in options:
37
+ if manual_unsupported:
38
+ raise UnsupportedThinkingError("Claude", model, "manual thinking budgets are not supported; use adaptive mode")
39
+ budget = options.get("budget_tokens")
40
+ if type(budget) is not int or budget < 1024:
41
+ raise UnsupportedThinkingError("Claude", model, "manual thinking requires thinking_budget (budget_tokens) >= 1024")
42
+ if params.get("max_tokens", params.get("max_output_tokens")) is None:
43
+ raise UnsupportedThinkingError("Claude", model, "manual thinking requires an explicit max_output_tokens allowance")
44
+ options["type"] = "enabled"
45
+ else:
46
+ options["type"] = "adaptive"
47
+ elif mode is not None:
48
+ if mode == "adaptive" and legacy:
49
+ raise UnsupportedThinkingError("Claude", model, "adaptive thinking is not supported by this model")
50
+ if mode == "adaptive" and "budget_tokens" in options:
51
+ raise UnsupportedThinkingError("Claude", model, "adaptive thinking uses effort, not budget_tokens")
52
+ if mode == "between_tools":
53
+ if not model.startswith("claude-sonnet-5-5"):
54
+ raise UnsupportedThinkingError("Claude", model, "between_tools is not supported by this model")
55
+ if output.get("effort") in {"xhigh", "max"}:
56
+ raise UnsupportedThinkingError("Claude", model, "between_tools does not support xhigh/max effort")
57
+ options["type"] = mode
58
+ if options:
59
+ params["thinking"] = options
60
+ if output:
61
+ params["output_config"] = output
62
+ else:
63
+ params.pop("output_config", None)