prompture 0.0.47__tar.gz → 0.0.47.dev2__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.47 → prompture-0.0.47.dev2}/PKG-INFO +1 -1
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/_version.py +2 -2
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/async_conversation.py +0 -16
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/conversation.py +0 -16
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_grok_driver.py +9 -23
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_groq_driver.py +9 -23
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_lmstudio_driver.py +2 -10
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_moonshot_driver.py +9 -20
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_openrouter_driver.py +17 -43
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/grok_driver.py +9 -23
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/groq_driver.py +9 -23
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/lmstudio_driver.py +2 -11
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/moonshot_driver.py +9 -20
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/openrouter_driver.py +10 -34
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/PKG-INFO +1 -1
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/SOURCES.txt +0 -1
- prompture-0.0.47/VERSION +0 -1
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-driver/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-driver/references/driver-template.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-example/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-field/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-persona/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-test/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/add-tool/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/run-tests/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.claude/skills/update-pricing/SKILL.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.env.copy +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/FUNDING.yml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/scripts/update_docs_version.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/scripts/update_wrapper_version.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/workflows/dev.yml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/workflows/documentation.yml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/.github/workflows/publish.yml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/CLAUDE.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/LICENSE +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/MANIFEST.in +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/README.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/ROADMAP.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/_static/custom.css +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/_templates/footer.html +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/core.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/drivers.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/field_definitions.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/index.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/runner.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/tools.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/api/validator.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/conf.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/contributing.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/examples.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/field_definitions_reference.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/index.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/installation.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/quickstart.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/docs/source/toon_input_guide.rst +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/README.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_json/README.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_json/pyproject.toml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_json/test.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_toon/README.md +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_toon/pyproject.toml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/packages/llm_to_toon/test.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/agent.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/agent_types.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/aio/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/async_agent.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/async_core.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/async_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/async_groups.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/cache.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/callbacks.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/cli.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/core.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/cost_mixin.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/discovery.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/airllm_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_airllm_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_azure_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_claude_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_google_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_hugging_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_local_http_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_modelscope_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_ollama_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_openai_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_registry.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/async_zai_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/azure_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/claude_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/google_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/hugging_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/local_http_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/modelscope_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/ollama_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/openai_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/registry.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/vision_helpers.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/drivers/zai_driver.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/field_definitions.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/group_types.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/groups.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/image.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/ledger.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/logging.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/model_rates.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/persistence.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/persona.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/runner.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/__init__.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/generator.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/README.md.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/config.py.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/env.example.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/main.py.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/models.py.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/serialization.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/server.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/session.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/settings.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/simulated_tools.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/tools.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/tools_schema.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture/validator.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/dependency_links.txt +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/entry_points.txt +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/requires.txt +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/prompture.egg-info/top_level.txt +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/pyproject.toml +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/requirements.txt +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/setup.cfg +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/test.py +0 -0
- {prompture-0.0.47 → prompture-0.0.47.dev2}/test_version_diagnosis.py +0 -0
|
@@ -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.47'
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0, 47)
|
|
31
|
+
__version__ = version = '0.0.47.dev2'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 47, 'dev2')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -109,9 +109,6 @@ class AsyncConversation:
|
|
|
109
109
|
self._max_tool_rounds = max_tool_rounds
|
|
110
110
|
self._simulated_tools = simulated_tools
|
|
111
111
|
|
|
112
|
-
# Reasoning content from last response
|
|
113
|
-
self._last_reasoning: str | None = None
|
|
114
|
-
|
|
115
112
|
# Persistence
|
|
116
113
|
self._conversation_id = conversation_id or str(uuid.uuid4())
|
|
117
114
|
self._auto_save = Path(auto_save) if auto_save else None
|
|
@@ -124,11 +121,6 @@ class AsyncConversation:
|
|
|
124
121
|
# Public helpers
|
|
125
122
|
# ------------------------------------------------------------------
|
|
126
123
|
|
|
127
|
-
@property
|
|
128
|
-
def last_reasoning(self) -> str | None:
|
|
129
|
-
"""The reasoning/thinking content from the last LLM response, if any."""
|
|
130
|
-
return self._last_reasoning
|
|
131
|
-
|
|
132
124
|
@property
|
|
133
125
|
def messages(self) -> list[dict[str, Any]]:
|
|
134
126
|
"""Read-only view of the conversation history."""
|
|
@@ -334,8 +326,6 @@ class AsyncConversation:
|
|
|
334
326
|
If tools are registered and the driver supports tool use,
|
|
335
327
|
dispatches to the async tool execution loop.
|
|
336
328
|
"""
|
|
337
|
-
self._last_reasoning = None
|
|
338
|
-
|
|
339
329
|
# Route to appropriate tool handling
|
|
340
330
|
if self._tools:
|
|
341
331
|
use_native = getattr(self._driver, "supports_tool_use", False)
|
|
@@ -350,7 +340,6 @@ class AsyncConversation:
|
|
|
350
340
|
|
|
351
341
|
text = resp.get("text", "")
|
|
352
342
|
meta = resp.get("meta", {})
|
|
353
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
354
343
|
|
|
355
344
|
user_content = self._build_content_with_images(content, images)
|
|
356
345
|
self._messages.append({"role": "user", "content": user_content})
|
|
@@ -383,7 +372,6 @@ class AsyncConversation:
|
|
|
383
372
|
text = resp.get("text", "")
|
|
384
373
|
|
|
385
374
|
if not tool_calls:
|
|
386
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
387
375
|
self._messages.append({"role": "assistant", "content": text})
|
|
388
376
|
return text
|
|
389
377
|
|
|
@@ -538,8 +526,6 @@ class AsyncConversation:
|
|
|
538
526
|
images: list[ImageInput] | None = None,
|
|
539
527
|
) -> dict[str, Any]:
|
|
540
528
|
"""Send a message with schema enforcement and get structured JSON back (async)."""
|
|
541
|
-
self._last_reasoning = None
|
|
542
|
-
|
|
543
529
|
merged = {**self._options, **(options or {})}
|
|
544
530
|
|
|
545
531
|
schema_string = json.dumps(json_schema, indent=2)
|
|
@@ -577,7 +563,6 @@ class AsyncConversation:
|
|
|
577
563
|
|
|
578
564
|
text = resp.get("text", "")
|
|
579
565
|
meta = resp.get("meta", {})
|
|
580
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
581
566
|
|
|
582
567
|
user_content = self._build_content_with_images(content, images)
|
|
583
568
|
self._messages.append({"role": "user", "content": user_content})
|
|
@@ -612,7 +597,6 @@ class AsyncConversation:
|
|
|
612
597
|
"json_object": json_obj,
|
|
613
598
|
"usage": usage,
|
|
614
599
|
"output_format": output_format,
|
|
615
|
-
"reasoning": self._last_reasoning,
|
|
616
600
|
}
|
|
617
601
|
|
|
618
602
|
if output_format == "toon":
|
|
@@ -112,9 +112,6 @@ class Conversation:
|
|
|
112
112
|
self._max_tool_rounds = max_tool_rounds
|
|
113
113
|
self._simulated_tools = simulated_tools
|
|
114
114
|
|
|
115
|
-
# Reasoning content from last response
|
|
116
|
-
self._last_reasoning: str | None = None
|
|
117
|
-
|
|
118
115
|
# Persistence
|
|
119
116
|
self._conversation_id = conversation_id or str(uuid.uuid4())
|
|
120
117
|
self._auto_save = Path(auto_save) if auto_save else None
|
|
@@ -127,11 +124,6 @@ class Conversation:
|
|
|
127
124
|
# Public helpers
|
|
128
125
|
# ------------------------------------------------------------------
|
|
129
126
|
|
|
130
|
-
@property
|
|
131
|
-
def last_reasoning(self) -> str | None:
|
|
132
|
-
"""The reasoning/thinking content from the last LLM response, if any."""
|
|
133
|
-
return self._last_reasoning
|
|
134
|
-
|
|
135
127
|
@property
|
|
136
128
|
def messages(self) -> list[dict[str, Any]]:
|
|
137
129
|
"""Read-only view of the conversation history."""
|
|
@@ -348,8 +340,6 @@ class Conversation:
|
|
|
348
340
|
images: Optional list of images to include (bytes, path, URL,
|
|
349
341
|
base64 string, or :class:`ImageContent`).
|
|
350
342
|
"""
|
|
351
|
-
self._last_reasoning = None
|
|
352
|
-
|
|
353
343
|
# Route to appropriate tool handling
|
|
354
344
|
if self._tools:
|
|
355
345
|
use_native = getattr(self._driver, "supports_tool_use", False)
|
|
@@ -364,7 +354,6 @@ class Conversation:
|
|
|
364
354
|
|
|
365
355
|
text = resp.get("text", "")
|
|
366
356
|
meta = resp.get("meta", {})
|
|
367
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
368
357
|
|
|
369
358
|
# Record in history — store content with images for context
|
|
370
359
|
user_content = self._build_content_with_images(content, images)
|
|
@@ -400,7 +389,6 @@ class Conversation:
|
|
|
400
389
|
|
|
401
390
|
if not tool_calls:
|
|
402
391
|
# No tool calls -> final response
|
|
403
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
404
392
|
self._messages.append({"role": "assistant", "content": text})
|
|
405
393
|
return text
|
|
406
394
|
|
|
@@ -565,8 +553,6 @@ class Conversation:
|
|
|
565
553
|
context clean for subsequent turns.
|
|
566
554
|
"""
|
|
567
555
|
|
|
568
|
-
self._last_reasoning = None
|
|
569
|
-
|
|
570
556
|
merged = {**self._options, **(options or {})}
|
|
571
557
|
|
|
572
558
|
# Build the full prompt with schema instructions inline (handled by ask_for_json)
|
|
@@ -608,7 +594,6 @@ class Conversation:
|
|
|
608
594
|
|
|
609
595
|
text = resp.get("text", "")
|
|
610
596
|
meta = resp.get("meta", {})
|
|
611
|
-
self._last_reasoning = resp.get("reasoning_content")
|
|
612
597
|
|
|
613
598
|
# Store original content (without schema boilerplate) for cleaner context
|
|
614
599
|
# Include images in history so subsequent turns can reference them
|
|
@@ -647,7 +632,6 @@ class Conversation:
|
|
|
647
632
|
"json_object": json_obj,
|
|
648
633
|
"usage": usage,
|
|
649
634
|
"output_format": output_format,
|
|
650
|
-
"reasoning": self._last_reasoning,
|
|
651
635
|
}
|
|
652
636
|
|
|
653
637
|
if output_format == "toon":
|
|
@@ -95,17 +95,8 @@ class AsyncGrokDriver(CostMixin, AsyncDriver):
|
|
|
95
95
|
"model_name": model,
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
reasoning_content = message.get("reasoning_content")
|
|
101
|
-
|
|
102
|
-
if not text and reasoning_content:
|
|
103
|
-
text = reasoning_content
|
|
104
|
-
|
|
105
|
-
result: dict[str, Any] = {"text": text, "meta": meta}
|
|
106
|
-
if reasoning_content is not None:
|
|
107
|
-
result["reasoning_content"] = reasoning_content
|
|
108
|
-
return result
|
|
98
|
+
text = resp["choices"][0]["message"]["content"]
|
|
99
|
+
return {"text": text, "meta": meta}
|
|
109
100
|
|
|
110
101
|
# ------------------------------------------------------------------
|
|
111
102
|
# Tool use
|
|
@@ -182,20 +173,15 @@ class AsyncGrokDriver(CostMixin, AsyncDriver):
|
|
|
182
173
|
args = json.loads(tc["function"]["arguments"])
|
|
183
174
|
except (json.JSONDecodeError, TypeError):
|
|
184
175
|
args = {}
|
|
185
|
-
tool_calls_out.append(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
result: dict[str, Any] = {
|
|
176
|
+
tool_calls_out.append({
|
|
177
|
+
"id": tc["id"],
|
|
178
|
+
"name": tc["function"]["name"],
|
|
179
|
+
"arguments": args,
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return {
|
|
194
183
|
"text": text,
|
|
195
184
|
"meta": meta,
|
|
196
185
|
"tool_calls": tool_calls_out,
|
|
197
186
|
"stop_reason": stop_reason,
|
|
198
187
|
}
|
|
199
|
-
if choice["message"].get("reasoning_content") is not None:
|
|
200
|
-
result["reasoning_content"] = choice["message"]["reasoning_content"]
|
|
201
|
-
return result
|
|
@@ -88,16 +88,8 @@ class AsyncGroqDriver(CostMixin, AsyncDriver):
|
|
|
88
88
|
"model_name": model,
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
text = resp.choices[0].message.content
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if not text and reasoning_content:
|
|
95
|
-
text = reasoning_content
|
|
96
|
-
|
|
97
|
-
result: dict[str, Any] = {"text": text, "meta": meta}
|
|
98
|
-
if reasoning_content is not None:
|
|
99
|
-
result["reasoning_content"] = reasoning_content
|
|
100
|
-
return result
|
|
91
|
+
text = resp.choices[0].message.content
|
|
92
|
+
return {"text": text, "meta": meta}
|
|
101
93
|
|
|
102
94
|
# ------------------------------------------------------------------
|
|
103
95
|
# Tool use
|
|
@@ -160,21 +152,15 @@ class AsyncGroqDriver(CostMixin, AsyncDriver):
|
|
|
160
152
|
args = json.loads(tc.function.arguments)
|
|
161
153
|
except (json.JSONDecodeError, TypeError):
|
|
162
154
|
args = {}
|
|
163
|
-
tool_calls_out.append(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
result: dict[str, Any] = {
|
|
155
|
+
tool_calls_out.append({
|
|
156
|
+
"id": tc.id,
|
|
157
|
+
"name": tc.function.name,
|
|
158
|
+
"arguments": args,
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return {
|
|
172
162
|
"text": text,
|
|
173
163
|
"meta": meta,
|
|
174
164
|
"tool_calls": tool_calls_out,
|
|
175
165
|
"stop_reason": stop_reason,
|
|
176
166
|
}
|
|
177
|
-
reasoning_content = getattr(choice.message, "reasoning_content", None)
|
|
178
|
-
if reasoning_content is not None:
|
|
179
|
-
result["reasoning_content"] = reasoning_content
|
|
180
|
-
return result
|
|
@@ -98,12 +98,7 @@ class AsyncLMStudioDriver(AsyncDriver):
|
|
|
98
98
|
if "choices" not in response_data or not response_data["choices"]:
|
|
99
99
|
raise ValueError(f"Unexpected response format: {response_data}")
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
text = message.get("content") or ""
|
|
103
|
-
reasoning_content = message.get("reasoning_content")
|
|
104
|
-
|
|
105
|
-
if not text and reasoning_content:
|
|
106
|
-
text = reasoning_content
|
|
101
|
+
text = response_data["choices"][0]["message"]["content"]
|
|
107
102
|
|
|
108
103
|
usage = response_data.get("usage", {})
|
|
109
104
|
prompt_tokens = usage.get("prompt_tokens", 0)
|
|
@@ -119,10 +114,7 @@ class AsyncLMStudioDriver(AsyncDriver):
|
|
|
119
114
|
"model_name": merged_options.get("model", self.model),
|
|
120
115
|
}
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
if reasoning_content is not None:
|
|
124
|
-
result["reasoning_content"] = reasoning_content
|
|
125
|
-
return result
|
|
117
|
+
return {"text": text, "meta": meta}
|
|
126
118
|
|
|
127
119
|
# -- Model management (LM Studio 0.4.0+) ----------------------------------
|
|
128
120
|
|
|
@@ -138,11 +138,10 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
138
138
|
|
|
139
139
|
message = resp["choices"][0]["message"]
|
|
140
140
|
text = message.get("content") or ""
|
|
141
|
-
reasoning_content = message.get("reasoning_content")
|
|
142
141
|
|
|
143
142
|
# Reasoning models may return content in reasoning_content when content is empty
|
|
144
|
-
if not text and reasoning_content:
|
|
145
|
-
text = reasoning_content
|
|
143
|
+
if not text and message.get("reasoning_content"):
|
|
144
|
+
text = message["reasoning_content"]
|
|
146
145
|
|
|
147
146
|
# Structured output fallback: if we used json_schema mode and got an
|
|
148
147
|
# empty response, retry with json_object mode and schema in the prompt.
|
|
@@ -185,9 +184,8 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
185
184
|
resp = fb_resp
|
|
186
185
|
fb_message = fb_resp["choices"][0]["message"]
|
|
187
186
|
text = fb_message.get("content") or ""
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
text = reasoning_content
|
|
187
|
+
if not text and fb_message.get("reasoning_content"):
|
|
188
|
+
text = fb_message["reasoning_content"]
|
|
191
189
|
|
|
192
190
|
total_cost = self._calculate_cost("moonshot", model, prompt_tokens, completion_tokens)
|
|
193
191
|
|
|
@@ -200,10 +198,7 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
200
198
|
"model_name": model,
|
|
201
199
|
}
|
|
202
200
|
|
|
203
|
-
|
|
204
|
-
if reasoning_content is not None:
|
|
205
|
-
result["reasoning_content"] = reasoning_content
|
|
206
|
-
return result
|
|
201
|
+
return {"text": text, "meta": meta}
|
|
207
202
|
|
|
208
203
|
# ------------------------------------------------------------------
|
|
209
204
|
# Tool use
|
|
@@ -339,7 +334,6 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
339
334
|
data["temperature"] = opts["temperature"]
|
|
340
335
|
|
|
341
336
|
full_text = ""
|
|
342
|
-
full_reasoning = ""
|
|
343
337
|
prompt_tokens = 0
|
|
344
338
|
completion_tokens = 0
|
|
345
339
|
|
|
@@ -374,11 +368,9 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
374
368
|
if choices:
|
|
375
369
|
delta = choices[0].get("delta", {})
|
|
376
370
|
content = delta.get("content") or ""
|
|
377
|
-
|
|
378
|
-
if
|
|
379
|
-
|
|
380
|
-
if not content and reasoning_chunk:
|
|
381
|
-
content = reasoning_chunk
|
|
371
|
+
# Reasoning models stream thinking via reasoning_content
|
|
372
|
+
if not content:
|
|
373
|
+
content = delta.get("reasoning_content") or ""
|
|
382
374
|
if content:
|
|
383
375
|
full_text += content
|
|
384
376
|
yield {"type": "delta", "text": content}
|
|
@@ -386,7 +378,7 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
386
378
|
total_tokens = prompt_tokens + completion_tokens
|
|
387
379
|
total_cost = self._calculate_cost("moonshot", model, prompt_tokens, completion_tokens)
|
|
388
380
|
|
|
389
|
-
|
|
381
|
+
yield {
|
|
390
382
|
"type": "done",
|
|
391
383
|
"text": full_text,
|
|
392
384
|
"meta": {
|
|
@@ -398,6 +390,3 @@ class AsyncMoonshotDriver(CostMixin, AsyncDriver):
|
|
|
398
390
|
"model_name": model,
|
|
399
391
|
},
|
|
400
392
|
}
|
|
401
|
-
if full_reasoning:
|
|
402
|
-
done_chunk["reasoning_content"] = full_reasoning
|
|
403
|
-
yield done_chunk
|
|
@@ -122,17 +122,8 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
122
122
|
"model_name": model,
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
reasoning_content = message.get("reasoning_content")
|
|
128
|
-
|
|
129
|
-
if not text and reasoning_content:
|
|
130
|
-
text = reasoning_content
|
|
131
|
-
|
|
132
|
-
result: dict[str, Any] = {"text": text, "meta": meta}
|
|
133
|
-
if reasoning_content is not None:
|
|
134
|
-
result["reasoning_content"] = reasoning_content
|
|
135
|
-
return result
|
|
125
|
+
text = resp["choices"][0]["message"]["content"]
|
|
126
|
+
return {"text": text, "meta": meta}
|
|
136
127
|
|
|
137
128
|
# ------------------------------------------------------------------
|
|
138
129
|
# Tool use
|
|
@@ -205,23 +196,18 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
205
196
|
args = json.loads(tc["function"]["arguments"])
|
|
206
197
|
except (json.JSONDecodeError, TypeError):
|
|
207
198
|
args = {}
|
|
208
|
-
tool_calls_out.append(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
)
|
|
199
|
+
tool_calls_out.append({
|
|
200
|
+
"id": tc["id"],
|
|
201
|
+
"name": tc["function"]["name"],
|
|
202
|
+
"arguments": args,
|
|
203
|
+
})
|
|
215
204
|
|
|
216
|
-
|
|
205
|
+
return {
|
|
217
206
|
"text": text,
|
|
218
207
|
"meta": meta,
|
|
219
208
|
"tool_calls": tool_calls_out,
|
|
220
209
|
"stop_reason": stop_reason,
|
|
221
210
|
}
|
|
222
|
-
if choice["message"].get("reasoning_content") is not None:
|
|
223
|
-
result["reasoning_content"] = choice["message"]["reasoning_content"]
|
|
224
|
-
return result
|
|
225
211
|
|
|
226
212
|
# ------------------------------------------------------------------
|
|
227
213
|
# Streaming
|
|
@@ -252,25 +238,21 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
252
238
|
data["temperature"] = opts["temperature"]
|
|
253
239
|
|
|
254
240
|
full_text = ""
|
|
255
|
-
full_reasoning = ""
|
|
256
241
|
prompt_tokens = 0
|
|
257
242
|
completion_tokens = 0
|
|
258
243
|
|
|
259
|
-
async with (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
timeout=120,
|
|
267
|
-
) as response,
|
|
268
|
-
):
|
|
244
|
+
async with httpx.AsyncClient() as client, client.stream(
|
|
245
|
+
"POST",
|
|
246
|
+
f"{self.base_url}/chat/completions",
|
|
247
|
+
headers=self.headers,
|
|
248
|
+
json=data,
|
|
249
|
+
timeout=120,
|
|
250
|
+
) as response:
|
|
269
251
|
response.raise_for_status()
|
|
270
252
|
async for line in response.aiter_lines():
|
|
271
253
|
if not line or not line.startswith("data: "):
|
|
272
254
|
continue
|
|
273
|
-
payload = line[len("data: ")
|
|
255
|
+
payload = line[len("data: "):]
|
|
274
256
|
if payload.strip() == "[DONE]":
|
|
275
257
|
break
|
|
276
258
|
try:
|
|
@@ -288,11 +270,6 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
288
270
|
if choices:
|
|
289
271
|
delta = choices[0].get("delta", {})
|
|
290
272
|
content = delta.get("content", "")
|
|
291
|
-
reasoning_chunk = delta.get("reasoning_content") or ""
|
|
292
|
-
if reasoning_chunk:
|
|
293
|
-
full_reasoning += reasoning_chunk
|
|
294
|
-
if not content and reasoning_chunk:
|
|
295
|
-
content = reasoning_chunk
|
|
296
273
|
if content:
|
|
297
274
|
full_text += content
|
|
298
275
|
yield {"type": "delta", "text": content}
|
|
@@ -300,7 +277,7 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
300
277
|
total_tokens = prompt_tokens + completion_tokens
|
|
301
278
|
total_cost = self._calculate_cost("openrouter", model, prompt_tokens, completion_tokens)
|
|
302
279
|
|
|
303
|
-
|
|
280
|
+
yield {
|
|
304
281
|
"type": "done",
|
|
305
282
|
"text": full_text,
|
|
306
283
|
"meta": {
|
|
@@ -312,6 +289,3 @@ class AsyncOpenRouterDriver(CostMixin, AsyncDriver):
|
|
|
312
289
|
"model_name": model,
|
|
313
290
|
},
|
|
314
291
|
}
|
|
315
|
-
if full_reasoning:
|
|
316
|
-
done_chunk["reasoning_content"] = full_reasoning
|
|
317
|
-
yield done_chunk
|
|
@@ -154,17 +154,8 @@ class GrokDriver(CostMixin, Driver):
|
|
|
154
154
|
"model_name": model,
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
reasoning_content = message.get("reasoning_content")
|
|
160
|
-
|
|
161
|
-
if not text and reasoning_content:
|
|
162
|
-
text = reasoning_content
|
|
163
|
-
|
|
164
|
-
result: dict[str, Any] = {"text": text, "meta": meta}
|
|
165
|
-
if reasoning_content is not None:
|
|
166
|
-
result["reasoning_content"] = reasoning_content
|
|
167
|
-
return result
|
|
157
|
+
text = resp["choices"][0]["message"]["content"]
|
|
158
|
+
return {"text": text, "meta": meta}
|
|
168
159
|
|
|
169
160
|
# ------------------------------------------------------------------
|
|
170
161
|
# Tool use
|
|
@@ -236,20 +227,15 @@ class GrokDriver(CostMixin, Driver):
|
|
|
236
227
|
args = json.loads(tc["function"]["arguments"])
|
|
237
228
|
except (json.JSONDecodeError, TypeError):
|
|
238
229
|
args = {}
|
|
239
|
-
tool_calls_out.append(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
result: dict[str, Any] = {
|
|
230
|
+
tool_calls_out.append({
|
|
231
|
+
"id": tc["id"],
|
|
232
|
+
"name": tc["function"]["name"],
|
|
233
|
+
"arguments": args,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return {
|
|
248
237
|
"text": text,
|
|
249
238
|
"meta": meta,
|
|
250
239
|
"tool_calls": tool_calls_out,
|
|
251
240
|
"stop_reason": stop_reason,
|
|
252
241
|
}
|
|
253
|
-
if choice["message"].get("reasoning_content") is not None:
|
|
254
|
-
result["reasoning_content"] = choice["message"]["reasoning_content"]
|
|
255
|
-
return result
|
|
@@ -122,16 +122,8 @@ class GroqDriver(CostMixin, Driver):
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
# Extract generated text
|
|
125
|
-
text = resp.choices[0].message.content
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if not text and reasoning_content:
|
|
129
|
-
text = reasoning_content
|
|
130
|
-
|
|
131
|
-
result: dict[str, Any] = {"text": text, "meta": meta}
|
|
132
|
-
if reasoning_content is not None:
|
|
133
|
-
result["reasoning_content"] = reasoning_content
|
|
134
|
-
return result
|
|
125
|
+
text = resp.choices[0].message.content
|
|
126
|
+
return {"text": text, "meta": meta}
|
|
135
127
|
|
|
136
128
|
# ------------------------------------------------------------------
|
|
137
129
|
# Tool use
|
|
@@ -194,21 +186,15 @@ class GroqDriver(CostMixin, Driver):
|
|
|
194
186
|
args = json.loads(tc.function.arguments)
|
|
195
187
|
except (json.JSONDecodeError, TypeError):
|
|
196
188
|
args = {}
|
|
197
|
-
tool_calls_out.append(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
result: dict[str, Any] = {
|
|
189
|
+
tool_calls_out.append({
|
|
190
|
+
"id": tc.id,
|
|
191
|
+
"name": tc.function.name,
|
|
192
|
+
"arguments": args,
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
return {
|
|
206
196
|
"text": text,
|
|
207
197
|
"meta": meta,
|
|
208
198
|
"tool_calls": tool_calls_out,
|
|
209
199
|
"stop_reason": stop_reason,
|
|
210
200
|
}
|
|
211
|
-
reasoning_content = getattr(choice.message, "reasoning_content", None)
|
|
212
|
-
if reasoning_content is not None:
|
|
213
|
-
result["reasoning_content"] = reasoning_content
|
|
214
|
-
return result
|
|
@@ -123,13 +123,7 @@ class LMStudioDriver(Driver):
|
|
|
123
123
|
raise RuntimeError(f"LM Studio request failed: {e}") from e
|
|
124
124
|
|
|
125
125
|
# Extract text
|
|
126
|
-
|
|
127
|
-
text = message.get("content") or ""
|
|
128
|
-
reasoning_content = message.get("reasoning_content")
|
|
129
|
-
|
|
130
|
-
# Reasoning models (e.g. DeepSeek R1) may return content in reasoning_content
|
|
131
|
-
if not text and reasoning_content:
|
|
132
|
-
text = reasoning_content
|
|
126
|
+
text = response_data["choices"][0]["message"]["content"]
|
|
133
127
|
|
|
134
128
|
# Meta info
|
|
135
129
|
usage = response_data.get("usage", {})
|
|
@@ -146,10 +140,7 @@ class LMStudioDriver(Driver):
|
|
|
146
140
|
"model_name": merged_options.get("model", self.model),
|
|
147
141
|
}
|
|
148
142
|
|
|
149
|
-
|
|
150
|
-
if reasoning_content is not None:
|
|
151
|
-
result["reasoning_content"] = reasoning_content
|
|
152
|
-
return result
|
|
143
|
+
return {"text": text, "meta": meta}
|
|
153
144
|
|
|
154
145
|
# -- Model management (LM Studio 0.4.0+) ----------------------------------
|
|
155
146
|
|