prompture 0.0.29.dev8__py3-none-any.whl → 0.0.38.dev2__py3-none-any.whl
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/__init__.py +264 -23
- prompture/_version.py +34 -0
- prompture/agent.py +924 -0
- prompture/agent_types.py +156 -0
- prompture/aio/__init__.py +74 -0
- prompture/async_agent.py +880 -0
- prompture/async_conversation.py +789 -0
- prompture/async_core.py +803 -0
- prompture/async_driver.py +193 -0
- prompture/async_groups.py +551 -0
- prompture/cache.py +469 -0
- prompture/callbacks.py +55 -0
- prompture/cli.py +63 -4
- prompture/conversation.py +826 -0
- prompture/core.py +894 -263
- prompture/cost_mixin.py +51 -0
- prompture/discovery.py +187 -0
- prompture/driver.py +206 -5
- prompture/drivers/__init__.py +175 -67
- prompture/drivers/airllm_driver.py +109 -0
- prompture/drivers/async_airllm_driver.py +26 -0
- prompture/drivers/async_azure_driver.py +123 -0
- prompture/drivers/async_claude_driver.py +113 -0
- prompture/drivers/async_google_driver.py +316 -0
- prompture/drivers/async_grok_driver.py +97 -0
- prompture/drivers/async_groq_driver.py +90 -0
- prompture/drivers/async_hugging_driver.py +61 -0
- prompture/drivers/async_lmstudio_driver.py +148 -0
- prompture/drivers/async_local_http_driver.py +44 -0
- prompture/drivers/async_ollama_driver.py +135 -0
- prompture/drivers/async_openai_driver.py +102 -0
- prompture/drivers/async_openrouter_driver.py +102 -0
- prompture/drivers/async_registry.py +133 -0
- prompture/drivers/azure_driver.py +42 -9
- prompture/drivers/claude_driver.py +257 -34
- prompture/drivers/google_driver.py +295 -42
- prompture/drivers/grok_driver.py +35 -32
- prompture/drivers/groq_driver.py +33 -26
- prompture/drivers/hugging_driver.py +6 -6
- prompture/drivers/lmstudio_driver.py +97 -19
- prompture/drivers/local_http_driver.py +6 -6
- prompture/drivers/ollama_driver.py +168 -23
- prompture/drivers/openai_driver.py +184 -9
- prompture/drivers/openrouter_driver.py +37 -25
- prompture/drivers/registry.py +306 -0
- prompture/drivers/vision_helpers.py +153 -0
- prompture/field_definitions.py +106 -96
- prompture/group_types.py +147 -0
- prompture/groups.py +530 -0
- prompture/image.py +180 -0
- prompture/logging.py +80 -0
- prompture/model_rates.py +217 -0
- prompture/persistence.py +254 -0
- prompture/persona.py +482 -0
- prompture/runner.py +49 -47
- prompture/scaffold/__init__.py +1 -0
- prompture/scaffold/generator.py +84 -0
- prompture/scaffold/templates/Dockerfile.j2 +12 -0
- prompture/scaffold/templates/README.md.j2 +41 -0
- prompture/scaffold/templates/config.py.j2 +21 -0
- prompture/scaffold/templates/env.example.j2 +8 -0
- prompture/scaffold/templates/main.py.j2 +86 -0
- prompture/scaffold/templates/models.py.j2 +40 -0
- prompture/scaffold/templates/requirements.txt.j2 +5 -0
- prompture/serialization.py +218 -0
- prompture/server.py +183 -0
- prompture/session.py +117 -0
- prompture/settings.py +19 -1
- prompture/tools.py +219 -267
- prompture/tools_schema.py +254 -0
- prompture/validator.py +3 -3
- prompture-0.0.38.dev2.dist-info/METADATA +369 -0
- prompture-0.0.38.dev2.dist-info/RECORD +77 -0
- {prompture-0.0.29.dev8.dist-info → prompture-0.0.38.dev2.dist-info}/WHEEL +1 -1
- prompture-0.0.29.dev8.dist-info/METADATA +0 -368
- prompture-0.0.29.dev8.dist-info/RECORD +0 -27
- {prompture-0.0.29.dev8.dist-info → prompture-0.0.38.dev2.dist-info}/entry_points.txt +0 -0
- {prompture-0.0.29.dev8.dist-info → prompture-0.0.38.dev2.dist-info}/licenses/LICENSE +0 -0
- {prompture-0.0.29.dev8.dist-info → prompture-0.0.38.dev2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Shared helpers for converting universal vision message blocks to provider-specific formats."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _prepare_openai_vision_messages(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
9
|
+
"""Convert universal image blocks to OpenAI-compatible vision format.
|
|
10
|
+
|
|
11
|
+
Works for OpenAI, Azure, Groq, Grok, LM Studio, and OpenRouter.
|
|
12
|
+
|
|
13
|
+
Universal format::
|
|
14
|
+
|
|
15
|
+
{"type": "image", "source": ImageContent(...)}
|
|
16
|
+
|
|
17
|
+
OpenAI format::
|
|
18
|
+
|
|
19
|
+
{"type": "image_url", "image_url": {"url": "data:mime;base64,..."}}
|
|
20
|
+
"""
|
|
21
|
+
out: list[dict[str, Any]] = []
|
|
22
|
+
for msg in messages:
|
|
23
|
+
content = msg.get("content")
|
|
24
|
+
if not isinstance(content, list):
|
|
25
|
+
out.append(msg)
|
|
26
|
+
continue
|
|
27
|
+
new_blocks: list[dict[str, Any]] = []
|
|
28
|
+
for block in content:
|
|
29
|
+
if isinstance(block, dict) and block.get("type") == "image":
|
|
30
|
+
source = block["source"]
|
|
31
|
+
if source.source_type == "url" and source.url:
|
|
32
|
+
url = source.url
|
|
33
|
+
else:
|
|
34
|
+
url = f"data:{source.media_type};base64,{source.data}"
|
|
35
|
+
new_blocks.append(
|
|
36
|
+
{
|
|
37
|
+
"type": "image_url",
|
|
38
|
+
"image_url": {"url": url},
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
new_blocks.append(block)
|
|
43
|
+
out.append({**msg, "content": new_blocks})
|
|
44
|
+
return out
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _prepare_claude_vision_messages(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
48
|
+
"""Convert universal image blocks to Anthropic Claude format.
|
|
49
|
+
|
|
50
|
+
Claude format::
|
|
51
|
+
|
|
52
|
+
{"type": "image", "source": {"type": "base64", "media_type": "...", "data": "..."}}
|
|
53
|
+
"""
|
|
54
|
+
out: list[dict[str, Any]] = []
|
|
55
|
+
for msg in messages:
|
|
56
|
+
content = msg.get("content")
|
|
57
|
+
if not isinstance(content, list):
|
|
58
|
+
out.append(msg)
|
|
59
|
+
continue
|
|
60
|
+
new_blocks: list[dict[str, Any]] = []
|
|
61
|
+
for block in content:
|
|
62
|
+
if isinstance(block, dict) and block.get("type") == "image":
|
|
63
|
+
source = block["source"]
|
|
64
|
+
if source.source_type == "url" and source.url:
|
|
65
|
+
new_blocks.append(
|
|
66
|
+
{
|
|
67
|
+
"type": "image",
|
|
68
|
+
"source": {
|
|
69
|
+
"type": "url",
|
|
70
|
+
"url": source.url,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
new_blocks.append(
|
|
76
|
+
{
|
|
77
|
+
"type": "image",
|
|
78
|
+
"source": {
|
|
79
|
+
"type": "base64",
|
|
80
|
+
"media_type": source.media_type,
|
|
81
|
+
"data": source.data,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
new_blocks.append(block)
|
|
87
|
+
out.append({**msg, "content": new_blocks})
|
|
88
|
+
return out
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _prepare_google_vision_messages(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
92
|
+
"""Convert universal image blocks to Google Gemini format.
|
|
93
|
+
|
|
94
|
+
Gemini expects ``parts`` arrays containing text and inline_data dicts::
|
|
95
|
+
|
|
96
|
+
{"role": "user", "parts": [
|
|
97
|
+
"text prompt",
|
|
98
|
+
{"inline_data": {"mime_type": "image/png", "data": "base64..."}},
|
|
99
|
+
]}
|
|
100
|
+
"""
|
|
101
|
+
out: list[dict[str, Any]] = []
|
|
102
|
+
for msg in messages:
|
|
103
|
+
content = msg.get("content")
|
|
104
|
+
if not isinstance(content, list):
|
|
105
|
+
out.append(msg)
|
|
106
|
+
continue
|
|
107
|
+
# Convert content blocks to Gemini parts
|
|
108
|
+
parts: list[Any] = []
|
|
109
|
+
for block in content:
|
|
110
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
111
|
+
parts.append(block["text"])
|
|
112
|
+
elif isinstance(block, dict) and block.get("type") == "image":
|
|
113
|
+
source = block["source"]
|
|
114
|
+
parts.append(
|
|
115
|
+
{
|
|
116
|
+
"inline_data": {
|
|
117
|
+
"mime_type": source.media_type,
|
|
118
|
+
"data": source.data,
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
else:
|
|
123
|
+
parts.append(block)
|
|
124
|
+
out.append({**msg, "content": parts, "_vision_parts": True})
|
|
125
|
+
return out
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _prepare_ollama_vision_messages(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
129
|
+
"""Convert universal image blocks to Ollama format.
|
|
130
|
+
|
|
131
|
+
Ollama expects images as a separate field::
|
|
132
|
+
|
|
133
|
+
{"role": "user", "content": "text", "images": ["base64..."]}
|
|
134
|
+
"""
|
|
135
|
+
out: list[dict[str, Any]] = []
|
|
136
|
+
for msg in messages:
|
|
137
|
+
content = msg.get("content")
|
|
138
|
+
if not isinstance(content, list):
|
|
139
|
+
out.append(msg)
|
|
140
|
+
continue
|
|
141
|
+
text_parts: list[str] = []
|
|
142
|
+
images: list[str] = []
|
|
143
|
+
for block in content:
|
|
144
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
145
|
+
text_parts.append(block["text"])
|
|
146
|
+
elif isinstance(block, dict) and block.get("type") == "image":
|
|
147
|
+
source = block["source"]
|
|
148
|
+
images.append(source.data)
|
|
149
|
+
new_msg = {**msg, "content": " ".join(text_parts)}
|
|
150
|
+
if images:
|
|
151
|
+
new_msg["images"] = images
|
|
152
|
+
out.append(new_msg)
|
|
153
|
+
return out
|