ai-pipeline-core 0.2.7__tar.gz → 0.2.9__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.
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/PKG-INFO +1 -1
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/__init__.py +1 -1
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/flow/options.py +2 -2
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/client.py +56 -21
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/model_response.py +6 -3
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/pyproject.toml +2 -2
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/.gitignore +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/LICENSE +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/README.md +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/document.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/document_list.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/flow_document.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/mime_type.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/task_document.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/temporary_document.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/utils.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/exceptions.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/flow/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/flow/config.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/ai_messages.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/model_options.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/llm/model_types.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/logging/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/logging/logging.yml +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/logging/logging_config.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/logging/logging_mixin.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/pipeline.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/prefect.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/prompt_manager.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/py.typed +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/settings.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/simple_runner/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/simple_runner/cli.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/simple_runner/simple_runner.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/storage/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/storage/storage.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/tracing.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/utils/__init__.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/utils/deploy.py +0 -0
- {ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/utils/remote_deployment.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-pipeline-core
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Core utilities for AI-powered processing pipelines using prefect
|
|
5
5
|
Project-URL: Homepage, https://github.com/bbarwik/ai-pipeline-core
|
|
6
6
|
Project-URL: Repository, https://github.com/bbarwik/ai-pipeline-core
|
|
@@ -61,11 +61,11 @@ class FlowOptions(BaseSettings):
|
|
|
61
61
|
"""
|
|
62
62
|
|
|
63
63
|
core_model: ModelName = Field(
|
|
64
|
-
default="
|
|
64
|
+
default="gemini-2.5-pro",
|
|
65
65
|
description="Primary model for complex analysis and generation tasks.",
|
|
66
66
|
)
|
|
67
67
|
small_model: ModelName = Field(
|
|
68
|
-
default="
|
|
68
|
+
default="grok-4-fast",
|
|
69
69
|
description="Fast, cost-effective model for simple tasks and orchestration.",
|
|
70
70
|
)
|
|
71
71
|
|
|
@@ -45,31 +45,30 @@ def _process_messages(
|
|
|
45
45
|
|
|
46
46
|
Internal function that combines context and messages into a single
|
|
47
47
|
list of API-compatible messages. Applies caching directives to
|
|
48
|
-
context messages for efficiency.
|
|
48
|
+
system prompt and context messages for efficiency.
|
|
49
49
|
|
|
50
50
|
Args:
|
|
51
51
|
context: Messages to be cached (typically expensive/static content).
|
|
52
52
|
messages: Regular messages without caching (dynamic queries).
|
|
53
53
|
system_prompt: Optional system instructions for the model.
|
|
54
|
-
cache_ttl: Cache TTL for context messages (e.g. "120s", "300s", "1h").
|
|
54
|
+
cache_ttl: Cache TTL for system and context messages (e.g. "120s", "300s", "1h").
|
|
55
55
|
Set to None or empty string to disable caching.
|
|
56
56
|
|
|
57
57
|
Returns:
|
|
58
58
|
List of formatted messages ready for API calls, with:
|
|
59
|
-
- System prompt at the beginning (if provided)
|
|
60
|
-
- Context messages with cache_control on
|
|
59
|
+
- System prompt at the beginning with cache_control (if provided and cache_ttl set)
|
|
60
|
+
- Context messages with cache_control on all messages (if cache_ttl set)
|
|
61
61
|
- Regular messages without caching
|
|
62
62
|
|
|
63
63
|
System Prompt Location:
|
|
64
64
|
The system prompt parameter is always injected as the FIRST message
|
|
65
|
-
with role="system". It is
|
|
66
|
-
system prompts without breaking cache efficiency.
|
|
65
|
+
with role="system". It is cached along with context when cache_ttl is set.
|
|
67
66
|
|
|
68
67
|
Cache behavior:
|
|
69
|
-
|
|
68
|
+
All system and context messages get ephemeral caching with specified TTL
|
|
70
69
|
to reduce token usage on repeated calls with same context.
|
|
71
70
|
If cache_ttl is None or empty string (falsy), no caching is applied.
|
|
72
|
-
|
|
71
|
+
All system and context messages receive cache_control to maximize cache efficiency.
|
|
73
72
|
|
|
74
73
|
Note:
|
|
75
74
|
This is an internal function used by _generate_with_retry().
|
|
@@ -79,26 +78,28 @@ def _process_messages(
|
|
|
79
78
|
|
|
80
79
|
# Add system prompt if provided
|
|
81
80
|
if system_prompt:
|
|
82
|
-
processed_messages.append({
|
|
81
|
+
processed_messages.append({
|
|
82
|
+
"role": "system",
|
|
83
|
+
"content": [{"type": "text", "text": system_prompt}],
|
|
84
|
+
})
|
|
83
85
|
|
|
84
86
|
# Process context messages with caching if provided
|
|
85
87
|
if context:
|
|
86
88
|
# Use AIMessages.to_prompt() for context
|
|
87
89
|
context_messages = context.to_prompt()
|
|
90
|
+
processed_messages.extend(context_messages)
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"type": "ephemeral",
|
|
93
|
-
"ttl": cache_ttl,
|
|
94
|
-
}
|
|
95
|
-
assert isinstance(context_messages[-1]["content"], list) # type: ignore
|
|
96
|
-
context_messages[-1]["content"][-1]["cache_control"] = { # type: ignore
|
|
92
|
+
if cache_ttl:
|
|
93
|
+
for message in processed_messages:
|
|
94
|
+
message["cache_control"] = { # type: ignore
|
|
97
95
|
"type": "ephemeral",
|
|
98
96
|
"ttl": cache_ttl,
|
|
99
97
|
}
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
if isinstance(message["content"], list): # type: ignore
|
|
99
|
+
message["content"][-1]["cache_control"] = { # type: ignore
|
|
100
|
+
"type": "ephemeral",
|
|
101
|
+
"ttl": cache_ttl,
|
|
102
|
+
}
|
|
102
103
|
|
|
103
104
|
# Process regular messages without caching
|
|
104
105
|
if messages:
|
|
@@ -108,6 +109,38 @@ def _process_messages(
|
|
|
108
109
|
return processed_messages
|
|
109
110
|
|
|
110
111
|
|
|
112
|
+
def _remove_cache_control(
|
|
113
|
+
messages: list[ChatCompletionMessageParam],
|
|
114
|
+
) -> list[ChatCompletionMessageParam]:
|
|
115
|
+
"""Remove cache control directives from messages.
|
|
116
|
+
|
|
117
|
+
Internal utility that strips cache_control fields from both message-level
|
|
118
|
+
and content-level entries. Used in retry logic when cache-related errors
|
|
119
|
+
occur during LLM API calls.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
messages: List of messages that may contain cache_control directives.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
The same message list (modified in-place) with all cache_control
|
|
126
|
+
fields removed from both messages and their content items.
|
|
127
|
+
|
|
128
|
+
Note:
|
|
129
|
+
This function modifies the input list in-place but also returns it
|
|
130
|
+
for convenience. Handles both list-based content (multipart) and
|
|
131
|
+
string content (simple messages).
|
|
132
|
+
"""
|
|
133
|
+
for message in messages:
|
|
134
|
+
if content := message.get("content"):
|
|
135
|
+
if isinstance(content, list):
|
|
136
|
+
for item in content:
|
|
137
|
+
if "cache_control" in item:
|
|
138
|
+
del item["cache_control"]
|
|
139
|
+
if "cache_control" in message:
|
|
140
|
+
del message["cache_control"]
|
|
141
|
+
return messages # type: ignore
|
|
142
|
+
|
|
143
|
+
|
|
111
144
|
def _model_name_to_openrouter_model(model: ModelName) -> str:
|
|
112
145
|
"""Convert a model name to an OpenRouter model name.
|
|
113
146
|
|
|
@@ -124,7 +157,7 @@ def _model_name_to_openrouter_model(model: ModelName) -> str:
|
|
|
124
157
|
if model == "grok-4-fast-search":
|
|
125
158
|
return "x-ai/grok-4-fast:online"
|
|
126
159
|
if model == "sonar-pro-search":
|
|
127
|
-
return "perplexity/sonar-
|
|
160
|
+
return "perplexity/sonar-pro-search"
|
|
128
161
|
if model.startswith("gemini"):
|
|
129
162
|
return f"google/{model}"
|
|
130
163
|
elif model.startswith("gpt"):
|
|
@@ -242,7 +275,7 @@ async def _generate_with_retry(
|
|
|
242
275
|
if not context and not messages:
|
|
243
276
|
raise ValueError("Either context or messages must be provided")
|
|
244
277
|
|
|
245
|
-
if "gemini" in model.lower() and context.approximate_tokens_count <
|
|
278
|
+
if "gemini" in model.lower() and context.approximate_tokens_count < 10000:
|
|
246
279
|
# Bug fix for minimum explicit context size for Gemini models
|
|
247
280
|
options.cache_ttl = None
|
|
248
281
|
|
|
@@ -272,6 +305,8 @@ async def _generate_with_retry(
|
|
|
272
305
|
if not isinstance(e, asyncio.TimeoutError):
|
|
273
306
|
# disable cache if it's not a timeout because it may cause an error
|
|
274
307
|
completion_kwargs["extra_body"]["cache"] = {"no-cache": True}
|
|
308
|
+
# sometimes there are issues with cache so cache is removed in case of failure
|
|
309
|
+
processed_messages = _remove_cache_control(processed_messages)
|
|
275
310
|
|
|
276
311
|
logger.warning(
|
|
277
312
|
f"LLM generation failed (attempt {attempt + 1}/{options.retries}): {e}",
|
|
@@ -88,10 +88,13 @@ class ModelResponse(ChatCompletion):
|
|
|
88
88
|
data = chat_completion.model_dump()
|
|
89
89
|
|
|
90
90
|
# fixes issue where the role is "assistantassistant" instead of "assistant"
|
|
91
|
+
valid_finish_reasons = {"stop", "length", "tool_calls", "content_filter", "function_call"}
|
|
91
92
|
for i in range(len(data["choices"])):
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
data["choices"][i]["message"]["role"] = "assistant"
|
|
94
|
+
# Only update finish_reason if it's not already a valid value
|
|
95
|
+
current_finish_reason = data["choices"][i].get("finish_reason")
|
|
96
|
+
if current_finish_reason not in valid_finish_reasons:
|
|
97
|
+
data["choices"][i]["finish_reason"] = "stop"
|
|
95
98
|
|
|
96
99
|
super().__init__(**data)
|
|
97
100
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ai-pipeline-core"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.9"
|
|
4
4
|
description = "Core utilities for AI-powered processing pipelines using prefect"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -178,7 +178,7 @@ reportIncompatibleVariableOverride = "error"
|
|
|
178
178
|
reportMissingParameterType = "warning"
|
|
179
179
|
|
|
180
180
|
[tool.bumpversion]
|
|
181
|
-
current_version = "0.2.
|
|
181
|
+
current_version = "0.2.9"
|
|
182
182
|
commit = true
|
|
183
183
|
tag = true
|
|
184
184
|
tag_name = "v{new_version}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/document_list.py
RENAMED
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/flow_document.py
RENAMED
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/task_document.py
RENAMED
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/documents/temporary_document.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/logging/logging_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/simple_runner/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/simple_runner/simple_runner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_pipeline_core-0.2.7 → ai_pipeline_core-0.2.9}/ai_pipeline_core/utils/remote_deployment.py
RENAMED
|
File without changes
|