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.
- hiyal-0.0.1/.github/dependabot.yml +9 -0
- hiyal-0.0.1/.github/scripts/check_version.py +29 -0
- hiyal-0.0.1/.github/workflows/ci.yml +120 -0
- hiyal-0.0.1/.github/workflows/release.yml +109 -0
- hiyal-0.0.1/.gitignore +22 -0
- hiyal-0.0.1/.python-version +1 -0
- hiyal-0.0.1/LICENSE +21 -0
- hiyal-0.0.1/PKG-INFO +39 -0
- hiyal-0.0.1/README.md +11 -0
- hiyal-0.0.1/docs/assets/logo.png +0 -0
- hiyal-0.0.1/pyproject.toml +51 -0
- hiyal-0.0.1/src/hiyal/__init__.py +1 -0
- hiyal-0.0.1/src/hiyal/models/__init__.py +20 -0
- hiyal-0.0.1/src/hiyal/models/anthropic/__init__.py +11 -0
- hiyal-0.0.1/src/hiyal/models/anthropic/llm.py +23 -0
- hiyal-0.0.1/src/hiyal/models/anthropic/thinking.py +63 -0
- hiyal-0.0.1/src/hiyal/models/anthropic/translator.py +379 -0
- hiyal-0.0.1/src/hiyal/models/anthropic/transport.py +40 -0
- hiyal-0.0.1/src/hiyal/models/bases/__init__.py +20 -0
- hiyal-0.0.1/src/hiyal/models/bases/async_llm_stream.py +94 -0
- hiyal-0.0.1/src/hiyal/models/bases/base_llm.py +223 -0
- hiyal-0.0.1/src/hiyal/models/bases/config_resolver.py +160 -0
- hiyal-0.0.1/src/hiyal/models/bases/llm_stream.py +89 -0
- hiyal-0.0.1/src/hiyal/models/bases/stream_accumulator.py +119 -0
- hiyal-0.0.1/src/hiyal/models/bases/translator.py +312 -0
- hiyal-0.0.1/src/hiyal/models/bases/transport.py +172 -0
- hiyal-0.0.1/src/hiyal/models/bases/types.py +6 -0
- hiyal-0.0.1/src/hiyal/models/deepseek/__init__.py +5 -0
- hiyal-0.0.1/src/hiyal/models/deepseek/llm.py +23 -0
- hiyal-0.0.1/src/hiyal/models/deepseek/translator.py +46 -0
- hiyal-0.0.1/src/hiyal/models/deepseek/transport.py +26 -0
- hiyal-0.0.1/src/hiyal/models/gemini/__init__.py +12 -0
- hiyal-0.0.1/src/hiyal/models/gemini/llm.py +21 -0
- hiyal-0.0.1/src/hiyal/models/gemini/thinking.py +82 -0
- hiyal-0.0.1/src/hiyal/models/gemini/translator.py +474 -0
- hiyal-0.0.1/src/hiyal/models/gemini/transport.py +155 -0
- hiyal-0.0.1/src/hiyal/models/llm.py +46 -0
- hiyal-0.0.1/src/hiyal/models/ollama/__init__.py +11 -0
- hiyal-0.0.1/src/hiyal/models/ollama/llm.py +25 -0
- hiyal-0.0.1/src/hiyal/models/ollama/request.py +110 -0
- hiyal-0.0.1/src/hiyal/models/ollama/thinking.py +65 -0
- hiyal-0.0.1/src/hiyal/models/ollama/translator.py +383 -0
- hiyal-0.0.1/src/hiyal/models/ollama/transport.py +105 -0
- hiyal-0.0.1/src/hiyal/models/openai/__init__.py +16 -0
- hiyal-0.0.1/src/hiyal/models/openai/chat_contents.py +216 -0
- hiyal-0.0.1/src/hiyal/models/openai/chat_translator.py +215 -0
- hiyal-0.0.1/src/hiyal/models/openai/llm.py +21 -0
- hiyal-0.0.1/src/hiyal/models/openai/translator.py +509 -0
- hiyal-0.0.1/src/hiyal/models/openai/transport.py +69 -0
- hiyal-0.0.1/src/hiyal/models/schemas/__init__.py +41 -0
- hiyal-0.0.1/src/hiyal/models/schemas/config.py +232 -0
- hiyal-0.0.1/src/hiyal/models/schemas/fields.py +39 -0
- hiyal-0.0.1/src/hiyal/models/schemas/response.py +208 -0
- hiyal-0.0.1/src/hiyal/models/schemas/stream.py +119 -0
- hiyal-0.0.1/src/hiyal/models/schemas/thinking.py +82 -0
- hiyal-0.0.1/src/hiyal/models/schemas/types.py +57 -0
- hiyal-0.0.1/src/hiyal/models/schemas/usage.py +79 -0
- hiyal-0.0.1/src/hiyal/prompts/__init__.py +4 -0
- hiyal-0.0.1/src/hiyal/prompts/media.py +250 -0
- hiyal-0.0.1/src/hiyal/prompts/messages.py +50 -0
- hiyal-0.0.1/src/hiyal/tools/__init__.py +14 -0
- hiyal-0.0.1/src/hiyal/tools/calls/__init__.py +0 -0
- hiyal-0.0.1/src/hiyal/tools/calls/anthropic.py +86 -0
- hiyal-0.0.1/src/hiyal/tools/calls/gemini.py +46 -0
- hiyal-0.0.1/src/hiyal/tools/calls/ollama.py +30 -0
- hiyal-0.0.1/src/hiyal/tools/calls/openai.py +106 -0
- hiyal-0.0.1/src/hiyal/tools/calls/responses.py +218 -0
- hiyal-0.0.1/src/hiyal/tools/calls/spec.py +456 -0
- hiyal-0.0.1/src/hiyal/tools/decorator.py +78 -0
- hiyal-0.0.1/src/hiyal/tools/introspection.py +275 -0
- hiyal-0.0.1/src/hiyal/utility/__init__.py +6 -0
- hiyal-0.0.1/src/hiyal/utility/dicts.py +31 -0
- hiyal-0.0.1/src/hiyal/utility/identifiers.py +10 -0
- hiyal-0.0.1/src/hiyal/utility/parsing.py +19 -0
- hiyal-0.0.1/src/hiyal/utility/timing.py +20 -0
- hiyal-0.0.1/tests/__init__.py +0 -0
- hiyal-0.0.1/tests/conftest.py +19 -0
- hiyal-0.0.1/tests/legacy/test_connection_overrides.py +519 -0
- hiyal-0.0.1/tests/legacy/test_gemini.py +304 -0
- hiyal-0.0.1/tests/legacy/test_llm_config.py +140 -0
- hiyal-0.0.1/tests/legacy/test_llm_factory.py +114 -0
- hiyal-0.0.1/tests/legacy/test_media.py +281 -0
- hiyal-0.0.1/tests/legacy/test_model_config.py +404 -0
- hiyal-0.0.1/tests/legacy/test_openai_tools.py +331 -0
- hiyal-0.0.1/tests/legacy/test_provider_tools.py +429 -0
- hiyal-0.0.1/tests/legacy/test_public_imports.py +28 -0
- hiyal-0.0.1/tests/legacy/test_thinking.py +394 -0
- hiyal-0.0.1/tests/legacy/test_tool_call.py +129 -0
- hiyal-0.0.1/tests/legacy/test_tool_decorator.py +628 -0
- hiyal-0.0.1/tests/legacy/test_tools_shorthand.py +109 -0
- hiyal-0.0.1/tests/models/__init__.py +0 -0
- hiyal-0.0.1/tests/models/anthropic/__init__.py +0 -0
- hiyal-0.0.1/tests/models/anthropic/test_anthropic.py +390 -0
- hiyal-0.0.1/tests/models/bases/__init__.py +0 -0
- hiyal-0.0.1/tests/models/bases/fakes.py +130 -0
- hiyal-0.0.1/tests/models/bases/test_base_llm.py +237 -0
- hiyal-0.0.1/tests/models/bases/test_config_resolver.py +222 -0
- hiyal-0.0.1/tests/models/bases/test_translator_base.py +212 -0
- hiyal-0.0.1/tests/models/bases/test_transport_and_streams.py +276 -0
- hiyal-0.0.1/tests/models/deepseek/__init__.py +0 -0
- hiyal-0.0.1/tests/models/deepseek/test_deepseek.py +175 -0
- hiyal-0.0.1/tests/models/gemini/__init__.py +0 -0
- hiyal-0.0.1/tests/models/gemini/test_gemini_translator.py +349 -0
- hiyal-0.0.1/tests/models/gemini/test_gemini_transport.py +203 -0
- hiyal-0.0.1/tests/models/ollama/__init__.py +0 -0
- hiyal-0.0.1/tests/models/ollama/test_ollama.py +476 -0
- hiyal-0.0.1/tests/models/openai/__init__.py +0 -0
- hiyal-0.0.1/tests/models/openai/test_chat_completions.py +219 -0
- hiyal-0.0.1/tests/models/openai/test_openai_e2e.py +244 -0
- hiyal-0.0.1/tests/models/openai/test_openai_translator.py +321 -0
- hiyal-0.0.1/tests/models/schemas/__init__.py +0 -0
- hiyal-0.0.1/tests/models/schemas/test_config.py +186 -0
- hiyal-0.0.1/tests/models/schemas/test_schemas.py +216 -0
- hiyal-0.0.1/tests/models/test_llm_factory_and_exports.py +77 -0
- hiyal-0.0.1/tests/prompts/__init__.py +0 -0
- hiyal-0.0.1/tests/prompts/test_media.py +315 -0
- hiyal-0.0.1/tests/prompts/test_messages.py +70 -0
- hiyal-0.0.1/tests/support.py +221 -0
- hiyal-0.0.1/tests/tools/__init__.py +0 -0
- hiyal-0.0.1/tests/tools/test_introspection_and_decorator.py +632 -0
- hiyal-0.0.1/tests/tools/test_specs.py +356 -0
- hiyal-0.0.1/tests/tools/test_tool_call_model.py +129 -0
- hiyal-0.0.1/tests/tools/test_tool_call_normalize.py +137 -0
- hiyal-0.0.1/tests/typing/tool_examples.py +45 -0
- hiyal-0.0.1/tests/utility/__init__.py +0 -0
- hiyal-0.0.1/tests/utility/test_utility.py +106 -0
|
@@ -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)
|