prompture 0.0.40.dev1__tar.gz → 0.0.41.dev1__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.
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.env.copy +18 -0
- {prompture-0.0.40.dev1/prompture.egg-info → prompture-0.0.41.dev1}/PKG-INFO +1 -1
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/_version.py +2 -2
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/__init__.py +39 -0
- prompture-0.0.41.dev1/prompture/drivers/async_modelscope_driver.py +286 -0
- prompture-0.0.41.dev1/prompture/drivers/async_moonshot_driver.py +311 -0
- prompture-0.0.41.dev1/prompture/drivers/async_openrouter_driver.py +290 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_registry.py +30 -0
- prompture-0.0.41.dev1/prompture/drivers/async_zai_driver.py +302 -0
- prompture-0.0.41.dev1/prompture/drivers/modelscope_driver.py +303 -0
- prompture-0.0.41.dev1/prompture/drivers/moonshot_driver.py +341 -0
- prompture-0.0.41.dev1/prompture/drivers/openrouter_driver.py +348 -0
- prompture-0.0.41.dev1/prompture/drivers/zai_driver.py +317 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/model_rates.py +2 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/settings.py +15 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1/prompture.egg-info}/PKG-INFO +1 -1
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture.egg-info/SOURCES.txt +6 -0
- prompture-0.0.40.dev1/prompture/drivers/async_openrouter_driver.py +0 -102
- prompture-0.0.40.dev1/prompture/drivers/openrouter_driver.py +0 -152
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/add-driver/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/add-driver/references/driver-template.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/add-example/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/add-field/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/add-test/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/run-tests/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.claude/skills/update-pricing/SKILL.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/FUNDING.yml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/scripts/update_docs_version.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/scripts/update_wrapper_version.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/workflows/dev.yml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/workflows/documentation.yml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/.github/workflows/publish.yml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/CLAUDE.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/LICENSE +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/MANIFEST.in +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/README.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/ROADMAP.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/_static/custom.css +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/_templates/footer.html +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/core.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/drivers.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/field_definitions.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/index.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/runner.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/tools.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/api/validator.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/conf.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/contributing.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/examples.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/field_definitions_reference.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/index.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/installation.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/quickstart.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/docs/source/toon_input_guide.rst +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/README.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_json/README.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_json/pyproject.toml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_json/test.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_toon/README.md +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_toon/pyproject.toml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/packages/llm_to_toon/test.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/__init__.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/agent.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/agent_types.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/aio/__init__.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/async_agent.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/async_conversation.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/async_core.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/async_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/async_groups.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/cache.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/callbacks.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/cli.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/conversation.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/core.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/cost_mixin.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/discovery.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/airllm_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_airllm_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_azure_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_claude_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_google_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_grok_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_groq_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_hugging_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_lmstudio_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_local_http_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_ollama_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/async_openai_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/azure_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/claude_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/google_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/grok_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/groq_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/hugging_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/lmstudio_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/local_http_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/ollama_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/openai_driver.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/registry.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/drivers/vision_helpers.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/field_definitions.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/group_types.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/groups.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/image.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/ledger.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/logging.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/persistence.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/persona.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/runner.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/__init__.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/generator.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/README.md.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/config.py.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/env.example.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/main.py.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/models.py.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/serialization.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/server.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/session.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/tools.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/tools_schema.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture/validator.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture.egg-info/dependency_links.txt +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture.egg-info/entry_points.txt +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture.egg-info/requires.txt +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/prompture.egg-info/top_level.txt +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/pyproject.toml +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/requirements.txt +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/setup.cfg +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/test.py +0 -0
- {prompture-0.0.40.dev1 → prompture-0.0.41.dev1}/test_version_diagnosis.py +0 -0
|
@@ -60,6 +60,24 @@ OPENROUTER_MODEL=openai/gpt-3.5-turbo
|
|
|
60
60
|
GROK_API_KEY=your-api-key-here
|
|
61
61
|
GROK_MODEL=grok-4-fast-reasoning
|
|
62
62
|
|
|
63
|
+
# Moonshot AI (Kimi) Configuration
|
|
64
|
+
# Required if AI_PROVIDER=moonshot
|
|
65
|
+
MOONSHOT_API_KEY=
|
|
66
|
+
MOONSHOT_MODEL=kimi-k2-0905-preview
|
|
67
|
+
MOONSHOT_ENDPOINT=https://api.moonshot.ai/v1
|
|
68
|
+
|
|
69
|
+
# Z.ai (Zhipu AI) Configuration
|
|
70
|
+
# Required if AI_PROVIDER=zai
|
|
71
|
+
ZHIPU_API_KEY=
|
|
72
|
+
ZHIPU_MODEL=glm-4.7
|
|
73
|
+
ZHIPU_ENDPOINT=https://api.z.ai/api/paas/v4
|
|
74
|
+
|
|
75
|
+
# ModelScope (Alibaba Cloud) Configuration
|
|
76
|
+
# Required if AI_PROVIDER=modelscope
|
|
77
|
+
MODELSCOPE_API_KEY=
|
|
78
|
+
MODELSCOPE_MODEL=Qwen/Qwen3-235B-A22B-Instruct-2507
|
|
79
|
+
MODELSCOPE_ENDPOINT=https://api-inference.modelscope.cn/v1
|
|
80
|
+
|
|
63
81
|
# AirLLM Configuration
|
|
64
82
|
AIRLLM_MODEL=meta-llama/Llama-2-7b-hf
|
|
65
83
|
AIRLLM_COMPRESSION=
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
|
31
|
+
__version__ = version = '0.0.41.dev1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 41, 'dev1')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -37,10 +37,13 @@ from .async_groq_driver import AsyncGroqDriver
|
|
|
37
37
|
from .async_hugging_driver import AsyncHuggingFaceDriver
|
|
38
38
|
from .async_lmstudio_driver import AsyncLMStudioDriver
|
|
39
39
|
from .async_local_http_driver import AsyncLocalHTTPDriver
|
|
40
|
+
from .async_modelscope_driver import AsyncModelScopeDriver
|
|
41
|
+
from .async_moonshot_driver import AsyncMoonshotDriver
|
|
40
42
|
from .async_ollama_driver import AsyncOllamaDriver
|
|
41
43
|
from .async_openai_driver import AsyncOpenAIDriver
|
|
42
44
|
from .async_openrouter_driver import AsyncOpenRouterDriver
|
|
43
45
|
from .async_registry import ASYNC_DRIVER_REGISTRY, get_async_driver, get_async_driver_for_model
|
|
46
|
+
from .async_zai_driver import AsyncZaiDriver
|
|
44
47
|
from .azure_driver import AzureDriver
|
|
45
48
|
from .claude_driver import ClaudeDriver
|
|
46
49
|
from .google_driver import GoogleDriver
|
|
@@ -48,6 +51,8 @@ from .grok_driver import GrokDriver
|
|
|
48
51
|
from .groq_driver import GroqDriver
|
|
49
52
|
from .lmstudio_driver import LMStudioDriver
|
|
50
53
|
from .local_http_driver import LocalHTTPDriver
|
|
54
|
+
from .modelscope_driver import ModelScopeDriver
|
|
55
|
+
from .moonshot_driver import MoonshotDriver
|
|
51
56
|
from .ollama_driver import OllamaDriver
|
|
52
57
|
from .openai_driver import OpenAIDriver
|
|
53
58
|
from .openrouter_driver import OpenRouterDriver
|
|
@@ -65,6 +70,7 @@ from .registry import (
|
|
|
65
70
|
unregister_async_driver,
|
|
66
71
|
unregister_driver,
|
|
67
72
|
)
|
|
73
|
+
from .zai_driver import ZaiDriver
|
|
68
74
|
|
|
69
75
|
# Register built-in sync drivers
|
|
70
76
|
register_driver(
|
|
@@ -123,6 +129,33 @@ register_driver(
|
|
|
123
129
|
lambda model=None: GrokDriver(api_key=settings.grok_api_key, model=model or settings.grok_model),
|
|
124
130
|
overwrite=True,
|
|
125
131
|
)
|
|
132
|
+
register_driver(
|
|
133
|
+
"moonshot",
|
|
134
|
+
lambda model=None: MoonshotDriver(
|
|
135
|
+
api_key=settings.moonshot_api_key,
|
|
136
|
+
model=model or settings.moonshot_model,
|
|
137
|
+
endpoint=settings.moonshot_endpoint,
|
|
138
|
+
),
|
|
139
|
+
overwrite=True,
|
|
140
|
+
)
|
|
141
|
+
register_driver(
|
|
142
|
+
"modelscope",
|
|
143
|
+
lambda model=None: ModelScopeDriver(
|
|
144
|
+
api_key=settings.modelscope_api_key,
|
|
145
|
+
model=model or settings.modelscope_model,
|
|
146
|
+
endpoint=settings.modelscope_endpoint,
|
|
147
|
+
),
|
|
148
|
+
overwrite=True,
|
|
149
|
+
)
|
|
150
|
+
register_driver(
|
|
151
|
+
"zai",
|
|
152
|
+
lambda model=None: ZaiDriver(
|
|
153
|
+
api_key=settings.zhipu_api_key,
|
|
154
|
+
model=model or settings.zhipu_model,
|
|
155
|
+
endpoint=settings.zhipu_endpoint,
|
|
156
|
+
),
|
|
157
|
+
overwrite=True,
|
|
158
|
+
)
|
|
126
159
|
register_driver(
|
|
127
160
|
"airllm",
|
|
128
161
|
lambda model=None: AirLLMDriver(
|
|
@@ -197,9 +230,12 @@ __all__ = [
|
|
|
197
230
|
"AsyncHuggingFaceDriver",
|
|
198
231
|
"AsyncLMStudioDriver",
|
|
199
232
|
"AsyncLocalHTTPDriver",
|
|
233
|
+
"AsyncModelScopeDriver",
|
|
234
|
+
"AsyncMoonshotDriver",
|
|
200
235
|
"AsyncOllamaDriver",
|
|
201
236
|
"AsyncOpenAIDriver",
|
|
202
237
|
"AsyncOpenRouterDriver",
|
|
238
|
+
"AsyncZaiDriver",
|
|
203
239
|
"AzureDriver",
|
|
204
240
|
"ClaudeDriver",
|
|
205
241
|
"GoogleDriver",
|
|
@@ -207,9 +243,12 @@ __all__ = [
|
|
|
207
243
|
"GroqDriver",
|
|
208
244
|
"LMStudioDriver",
|
|
209
245
|
"LocalHTTPDriver",
|
|
246
|
+
"ModelScopeDriver",
|
|
247
|
+
"MoonshotDriver",
|
|
210
248
|
"OllamaDriver",
|
|
211
249
|
"OpenAIDriver",
|
|
212
250
|
"OpenRouterDriver",
|
|
251
|
+
"ZaiDriver",
|
|
213
252
|
"get_async_driver",
|
|
214
253
|
"get_async_driver_for_model",
|
|
215
254
|
# Factory functions
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""Async ModelScope (Alibaba Cloud) driver using httpx.
|
|
2
|
+
|
|
3
|
+
No hardcoded pricing — ModelScope's free tier has no per-token cost.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from collections.abc import AsyncIterator
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
|
|
15
|
+
from ..async_driver import AsyncDriver
|
|
16
|
+
from ..cost_mixin import CostMixin
|
|
17
|
+
from .modelscope_driver import ModelScopeDriver
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AsyncModelScopeDriver(CostMixin, AsyncDriver):
|
|
21
|
+
supports_json_mode = True
|
|
22
|
+
supports_json_schema = False
|
|
23
|
+
supports_tool_use = True
|
|
24
|
+
supports_streaming = True
|
|
25
|
+
supports_vision = False
|
|
26
|
+
|
|
27
|
+
MODEL_PRICING = ModelScopeDriver.MODEL_PRICING
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
api_key: str | None = None,
|
|
32
|
+
model: str = "Qwen/Qwen3-235B-A22B-Instruct-2507",
|
|
33
|
+
endpoint: str = "https://api-inference.modelscope.cn/v1",
|
|
34
|
+
):
|
|
35
|
+
self.api_key = api_key or os.getenv("MODELSCOPE_API_KEY")
|
|
36
|
+
if not self.api_key:
|
|
37
|
+
raise ValueError("ModelScope API key not found. Set MODELSCOPE_API_KEY env var.")
|
|
38
|
+
self.model = model
|
|
39
|
+
self.base_url = endpoint.rstrip("/")
|
|
40
|
+
self.headers = {
|
|
41
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
supports_messages = True
|
|
46
|
+
|
|
47
|
+
async def generate(self, prompt: str, options: dict[str, Any]) -> dict[str, Any]:
|
|
48
|
+
messages = [{"role": "user", "content": prompt}]
|
|
49
|
+
return await self._do_generate(messages, options)
|
|
50
|
+
|
|
51
|
+
async def generate_messages(self, messages: list[dict[str, str]], options: dict[str, Any]) -> dict[str, Any]:
|
|
52
|
+
return await self._do_generate(messages, options)
|
|
53
|
+
|
|
54
|
+
async def _do_generate(self, messages: list[dict[str, str]], options: dict[str, Any]) -> dict[str, Any]:
|
|
55
|
+
model = options.get("model", self.model)
|
|
56
|
+
|
|
57
|
+
model_config = self._get_model_config("modelscope", model)
|
|
58
|
+
tokens_param = model_config["tokens_param"]
|
|
59
|
+
supports_temperature = model_config["supports_temperature"]
|
|
60
|
+
|
|
61
|
+
self._validate_model_capabilities(
|
|
62
|
+
"modelscope",
|
|
63
|
+
model,
|
|
64
|
+
using_json_schema=bool(options.get("json_schema")),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
opts = {"temperature": 1.0, "max_tokens": 512, **options}
|
|
68
|
+
|
|
69
|
+
data: dict[str, Any] = {
|
|
70
|
+
"model": model,
|
|
71
|
+
"messages": messages,
|
|
72
|
+
}
|
|
73
|
+
data[tokens_param] = opts.get("max_tokens", 512)
|
|
74
|
+
|
|
75
|
+
if supports_temperature and "temperature" in opts:
|
|
76
|
+
data["temperature"] = opts["temperature"]
|
|
77
|
+
|
|
78
|
+
if options.get("json_mode"):
|
|
79
|
+
data["response_format"] = {"type": "json_object"}
|
|
80
|
+
|
|
81
|
+
async with httpx.AsyncClient() as client:
|
|
82
|
+
try:
|
|
83
|
+
response = await client.post(
|
|
84
|
+
f"{self.base_url}/chat/completions",
|
|
85
|
+
headers=self.headers,
|
|
86
|
+
json=data,
|
|
87
|
+
timeout=120,
|
|
88
|
+
)
|
|
89
|
+
response.raise_for_status()
|
|
90
|
+
resp = response.json()
|
|
91
|
+
except httpx.HTTPStatusError as e:
|
|
92
|
+
error_msg = f"ModelScope API request failed: {e!s}"
|
|
93
|
+
raise RuntimeError(error_msg) from e
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise RuntimeError(f"ModelScope API request failed: {e!s}") from e
|
|
96
|
+
|
|
97
|
+
usage = resp.get("usage", {})
|
|
98
|
+
prompt_tokens = usage.get("prompt_tokens", 0)
|
|
99
|
+
completion_tokens = usage.get("completion_tokens", 0)
|
|
100
|
+
total_tokens = usage.get("total_tokens", 0)
|
|
101
|
+
|
|
102
|
+
total_cost = self._calculate_cost("modelscope", model, prompt_tokens, completion_tokens)
|
|
103
|
+
|
|
104
|
+
meta = {
|
|
105
|
+
"prompt_tokens": prompt_tokens,
|
|
106
|
+
"completion_tokens": completion_tokens,
|
|
107
|
+
"total_tokens": total_tokens,
|
|
108
|
+
"cost": round(total_cost, 6),
|
|
109
|
+
"raw_response": resp,
|
|
110
|
+
"model_name": model,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
text = resp["choices"][0]["message"]["content"]
|
|
114
|
+
return {"text": text, "meta": meta}
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------------
|
|
117
|
+
# Tool use
|
|
118
|
+
# ------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
async def generate_messages_with_tools(
|
|
121
|
+
self,
|
|
122
|
+
messages: list[dict[str, Any]],
|
|
123
|
+
tools: list[dict[str, Any]],
|
|
124
|
+
options: dict[str, Any],
|
|
125
|
+
) -> dict[str, Any]:
|
|
126
|
+
"""Generate a response that may include tool calls."""
|
|
127
|
+
model = options.get("model", self.model)
|
|
128
|
+
model_config = self._get_model_config("modelscope", model)
|
|
129
|
+
tokens_param = model_config["tokens_param"]
|
|
130
|
+
supports_temperature = model_config["supports_temperature"]
|
|
131
|
+
|
|
132
|
+
self._validate_model_capabilities("modelscope", model, using_tool_use=True)
|
|
133
|
+
|
|
134
|
+
opts = {"temperature": 1.0, "max_tokens": 512, **options}
|
|
135
|
+
|
|
136
|
+
data: dict[str, Any] = {
|
|
137
|
+
"model": model,
|
|
138
|
+
"messages": messages,
|
|
139
|
+
"tools": tools,
|
|
140
|
+
}
|
|
141
|
+
data[tokens_param] = opts.get("max_tokens", 512)
|
|
142
|
+
|
|
143
|
+
if supports_temperature and "temperature" in opts:
|
|
144
|
+
data["temperature"] = opts["temperature"]
|
|
145
|
+
|
|
146
|
+
if "tool_choice" in options:
|
|
147
|
+
data["tool_choice"] = options["tool_choice"]
|
|
148
|
+
|
|
149
|
+
async with httpx.AsyncClient() as client:
|
|
150
|
+
try:
|
|
151
|
+
response = await client.post(
|
|
152
|
+
f"{self.base_url}/chat/completions",
|
|
153
|
+
headers=self.headers,
|
|
154
|
+
json=data,
|
|
155
|
+
timeout=120,
|
|
156
|
+
)
|
|
157
|
+
response.raise_for_status()
|
|
158
|
+
resp = response.json()
|
|
159
|
+
except httpx.HTTPStatusError as e:
|
|
160
|
+
error_msg = f"ModelScope API request failed: {e!s}"
|
|
161
|
+
raise RuntimeError(error_msg) from e
|
|
162
|
+
except Exception as e:
|
|
163
|
+
raise RuntimeError(f"ModelScope API request failed: {e!s}") from e
|
|
164
|
+
|
|
165
|
+
usage = resp.get("usage", {})
|
|
166
|
+
prompt_tokens = usage.get("prompt_tokens", 0)
|
|
167
|
+
completion_tokens = usage.get("completion_tokens", 0)
|
|
168
|
+
total_tokens = usage.get("total_tokens", 0)
|
|
169
|
+
total_cost = self._calculate_cost("modelscope", model, prompt_tokens, completion_tokens)
|
|
170
|
+
|
|
171
|
+
meta = {
|
|
172
|
+
"prompt_tokens": prompt_tokens,
|
|
173
|
+
"completion_tokens": completion_tokens,
|
|
174
|
+
"total_tokens": total_tokens,
|
|
175
|
+
"cost": round(total_cost, 6),
|
|
176
|
+
"raw_response": resp,
|
|
177
|
+
"model_name": model,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
choice = resp["choices"][0]
|
|
181
|
+
text = choice["message"].get("content") or ""
|
|
182
|
+
stop_reason = choice.get("finish_reason")
|
|
183
|
+
|
|
184
|
+
tool_calls_out: list[dict[str, Any]] = []
|
|
185
|
+
for tc in choice["message"].get("tool_calls", []):
|
|
186
|
+
try:
|
|
187
|
+
args = json.loads(tc["function"]["arguments"])
|
|
188
|
+
except (json.JSONDecodeError, TypeError):
|
|
189
|
+
args = {}
|
|
190
|
+
tool_calls_out.append(
|
|
191
|
+
{
|
|
192
|
+
"id": tc["id"],
|
|
193
|
+
"name": tc["function"]["name"],
|
|
194
|
+
"arguments": args,
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
"text": text,
|
|
200
|
+
"meta": meta,
|
|
201
|
+
"tool_calls": tool_calls_out,
|
|
202
|
+
"stop_reason": stop_reason,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# ------------------------------------------------------------------
|
|
206
|
+
# Streaming
|
|
207
|
+
# ------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
async def generate_messages_stream(
|
|
210
|
+
self,
|
|
211
|
+
messages: list[dict[str, Any]],
|
|
212
|
+
options: dict[str, Any],
|
|
213
|
+
) -> AsyncIterator[dict[str, Any]]:
|
|
214
|
+
"""Yield response chunks via ModelScope streaming API."""
|
|
215
|
+
model = options.get("model", self.model)
|
|
216
|
+
model_config = self._get_model_config("modelscope", model)
|
|
217
|
+
tokens_param = model_config["tokens_param"]
|
|
218
|
+
supports_temperature = model_config["supports_temperature"]
|
|
219
|
+
|
|
220
|
+
opts = {"temperature": 1.0, "max_tokens": 512, **options}
|
|
221
|
+
|
|
222
|
+
data: dict[str, Any] = {
|
|
223
|
+
"model": model,
|
|
224
|
+
"messages": messages,
|
|
225
|
+
"stream": True,
|
|
226
|
+
"stream_options": {"include_usage": True},
|
|
227
|
+
}
|
|
228
|
+
data[tokens_param] = opts.get("max_tokens", 512)
|
|
229
|
+
|
|
230
|
+
if supports_temperature and "temperature" in opts:
|
|
231
|
+
data["temperature"] = opts["temperature"]
|
|
232
|
+
|
|
233
|
+
full_text = ""
|
|
234
|
+
prompt_tokens = 0
|
|
235
|
+
completion_tokens = 0
|
|
236
|
+
|
|
237
|
+
async with (
|
|
238
|
+
httpx.AsyncClient() as client,
|
|
239
|
+
client.stream(
|
|
240
|
+
"POST",
|
|
241
|
+
f"{self.base_url}/chat/completions",
|
|
242
|
+
headers=self.headers,
|
|
243
|
+
json=data,
|
|
244
|
+
timeout=120,
|
|
245
|
+
) as response,
|
|
246
|
+
):
|
|
247
|
+
response.raise_for_status()
|
|
248
|
+
async for line in response.aiter_lines():
|
|
249
|
+
if not line or not line.startswith("data: "):
|
|
250
|
+
continue
|
|
251
|
+
payload = line[len("data: ") :]
|
|
252
|
+
if payload.strip() == "[DONE]":
|
|
253
|
+
break
|
|
254
|
+
try:
|
|
255
|
+
chunk = json.loads(payload)
|
|
256
|
+
except json.JSONDecodeError:
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
usage = chunk.get("usage")
|
|
260
|
+
if usage:
|
|
261
|
+
prompt_tokens = usage.get("prompt_tokens", 0)
|
|
262
|
+
completion_tokens = usage.get("completion_tokens", 0)
|
|
263
|
+
|
|
264
|
+
choices = chunk.get("choices", [])
|
|
265
|
+
if choices:
|
|
266
|
+
delta = choices[0].get("delta", {})
|
|
267
|
+
content = delta.get("content", "")
|
|
268
|
+
if content:
|
|
269
|
+
full_text += content
|
|
270
|
+
yield {"type": "delta", "text": content}
|
|
271
|
+
|
|
272
|
+
total_tokens = prompt_tokens + completion_tokens
|
|
273
|
+
total_cost = self._calculate_cost("modelscope", model, prompt_tokens, completion_tokens)
|
|
274
|
+
|
|
275
|
+
yield {
|
|
276
|
+
"type": "done",
|
|
277
|
+
"text": full_text,
|
|
278
|
+
"meta": {
|
|
279
|
+
"prompt_tokens": prompt_tokens,
|
|
280
|
+
"completion_tokens": completion_tokens,
|
|
281
|
+
"total_tokens": total_tokens,
|
|
282
|
+
"cost": round(total_cost, 6),
|
|
283
|
+
"raw_response": {},
|
|
284
|
+
"model_name": model,
|
|
285
|
+
},
|
|
286
|
+
}
|