ai-pipeline-core 0.1.12__py3-none-any.whl → 0.1.14__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.
- ai_pipeline_core/__init__.py +5 -2
- ai_pipeline_core/documents/__init__.py +2 -1
- ai_pipeline_core/documents/document.py +239 -14
- ai_pipeline_core/documents/document_list.py +72 -16
- ai_pipeline_core/documents/flow_document.py +6 -23
- ai_pipeline_core/documents/task_document.py +6 -23
- ai_pipeline_core/documents/temporary_document.py +5 -19
- ai_pipeline_core/documents/utils.py +64 -1
- ai_pipeline_core/flow/options.py +2 -2
- ai_pipeline_core/llm/__init__.py +5 -0
- ai_pipeline_core/llm/ai_messages.py +0 -3
- ai_pipeline_core/llm/client.py +50 -19
- ai_pipeline_core/llm/model_options.py +18 -0
- ai_pipeline_core/llm/model_response.py +62 -15
- ai_pipeline_core/llm/model_types.py +38 -36
- ai_pipeline_core/pipeline.py +28 -2
- ai_pipeline_core/settings.py +4 -0
- ai_pipeline_core/simple_runner/simple_runner.py +18 -1
- ai_pipeline_core/tracing.py +115 -7
- {ai_pipeline_core-0.1.12.dist-info → ai_pipeline_core-0.1.14.dist-info}/METADATA +42 -7
- ai_pipeline_core-0.1.14.dist-info/RECORD +36 -0
- ai_pipeline_core-0.1.12.dist-info/RECORD +0 -36
- {ai_pipeline_core-0.1.12.dist-info → ai_pipeline_core-0.1.14.dist-info}/WHEEL +0 -0
- {ai_pipeline_core-0.1.12.dist-info → ai_pipeline_core-0.1.14.dist-info}/licenses/LICENSE +0 -0
ai_pipeline_core/pipeline.py
CHANGED
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import datetime
|
|
12
12
|
import inspect
|
|
13
|
+
from functools import wraps
|
|
13
14
|
from typing import (
|
|
14
15
|
Any,
|
|
15
16
|
Callable,
|
|
@@ -36,7 +37,7 @@ from typing_extensions import TypeAlias
|
|
|
36
37
|
|
|
37
38
|
from ai_pipeline_core.documents import DocumentList
|
|
38
39
|
from ai_pipeline_core.flow.options import FlowOptions
|
|
39
|
-
from ai_pipeline_core.tracing import TraceLevel, trace
|
|
40
|
+
from ai_pipeline_core.tracing import TraceLevel, set_trace_cost, trace
|
|
40
41
|
|
|
41
42
|
# --------------------------------------------------------------------------- #
|
|
42
43
|
# Public callback aliases (Prefect stubs omit these exact types)
|
|
@@ -224,6 +225,7 @@ def pipeline_task(
|
|
|
224
225
|
trace_ignore_inputs: list[str] | None = None,
|
|
225
226
|
trace_input_formatter: Callable[..., str] | None = None,
|
|
226
227
|
trace_output_formatter: Callable[..., str] | None = None,
|
|
228
|
+
trace_cost: float | None = None,
|
|
227
229
|
# prefect passthrough
|
|
228
230
|
name: str | None = None,
|
|
229
231
|
description: str | None = None,
|
|
@@ -263,6 +265,7 @@ def pipeline_task(
|
|
|
263
265
|
trace_ignore_inputs: list[str] | None = None,
|
|
264
266
|
trace_input_formatter: Callable[..., str] | None = None,
|
|
265
267
|
trace_output_formatter: Callable[..., str] | None = None,
|
|
268
|
+
trace_cost: float | None = None,
|
|
266
269
|
# prefect passthrough
|
|
267
270
|
name: str | None = None,
|
|
268
271
|
description: str | None = None,
|
|
@@ -316,6 +319,9 @@ def pipeline_task(
|
|
|
316
319
|
trace_ignore_inputs: List of parameter names to exclude from tracing.
|
|
317
320
|
trace_input_formatter: Custom formatter for input tracing.
|
|
318
321
|
trace_output_formatter: Custom formatter for output tracing.
|
|
322
|
+
trace_cost: Optional cost value to track in metadata. When provided and > 0,
|
|
323
|
+
sets gen_ai.usage.output_cost, gen_ai.usage.cost, and cost metadata.
|
|
324
|
+
Also forces trace level to "always" if not already set.
|
|
319
325
|
|
|
320
326
|
Prefect task parameters:
|
|
321
327
|
name: Task name (defaults to function name).
|
|
@@ -405,6 +411,19 @@ def pipeline_task(
|
|
|
405
411
|
)
|
|
406
412
|
|
|
407
413
|
fname = _callable_name(fn, "task")
|
|
414
|
+
|
|
415
|
+
# Create wrapper to handle trace_cost if provided
|
|
416
|
+
@wraps(fn)
|
|
417
|
+
async def _wrapper(*args: Any, **kwargs: Any) -> R_co:
|
|
418
|
+
result = await fn(*args, **kwargs)
|
|
419
|
+
if trace_cost is not None and trace_cost > 0:
|
|
420
|
+
set_trace_cost(trace_cost)
|
|
421
|
+
return result
|
|
422
|
+
|
|
423
|
+
# Preserve the original function name for Prefect
|
|
424
|
+
_wrapper.__name__ = fname
|
|
425
|
+
_wrapper.__qualname__ = getattr(fn, "__qualname__", fname)
|
|
426
|
+
|
|
408
427
|
traced_fn = trace(
|
|
409
428
|
level=trace_level,
|
|
410
429
|
name=name or fname,
|
|
@@ -413,7 +432,7 @@ def pipeline_task(
|
|
|
413
432
|
ignore_inputs=trace_ignore_inputs,
|
|
414
433
|
input_formatter=trace_input_formatter,
|
|
415
434
|
output_formatter=trace_output_formatter,
|
|
416
|
-
)(
|
|
435
|
+
)(_wrapper)
|
|
417
436
|
|
|
418
437
|
return cast(
|
|
419
438
|
_TaskLike[R_co],
|
|
@@ -463,6 +482,7 @@ def pipeline_flow(
|
|
|
463
482
|
trace_ignore_inputs: list[str] | None = None,
|
|
464
483
|
trace_input_formatter: Callable[..., str] | None = None,
|
|
465
484
|
trace_output_formatter: Callable[..., str] | None = None,
|
|
485
|
+
trace_cost: float | None = None,
|
|
466
486
|
# prefect passthrough
|
|
467
487
|
name: str | None = None,
|
|
468
488
|
version: str | None = None,
|
|
@@ -497,6 +517,7 @@ def pipeline_flow(
|
|
|
497
517
|
trace_ignore_inputs: list[str] | None = None,
|
|
498
518
|
trace_input_formatter: Callable[..., str] | None = None,
|
|
499
519
|
trace_output_formatter: Callable[..., str] | None = None,
|
|
520
|
+
trace_cost: float | None = None,
|
|
500
521
|
# prefect passthrough
|
|
501
522
|
name: str | None = None,
|
|
502
523
|
version: str | None = None,
|
|
@@ -557,6 +578,9 @@ def pipeline_flow(
|
|
|
557
578
|
trace_ignore_inputs: Parameter names to exclude from tracing.
|
|
558
579
|
trace_input_formatter: Custom input formatter.
|
|
559
580
|
trace_output_formatter: Custom output formatter.
|
|
581
|
+
trace_cost: Optional cost value to track in metadata. When provided and > 0,
|
|
582
|
+
sets gen_ai.usage.output_cost, gen_ai.usage.cost, and cost metadata.
|
|
583
|
+
Also forces trace level to "always" if not already set.
|
|
560
584
|
|
|
561
585
|
Prefect flow parameters:
|
|
562
586
|
name: Flow name (defaults to function name).
|
|
@@ -666,6 +690,8 @@ def pipeline_flow(
|
|
|
666
690
|
**kwargs: Any,
|
|
667
691
|
) -> DocumentList:
|
|
668
692
|
result = await fn(project_name, documents, flow_options, *args, **kwargs)
|
|
693
|
+
if trace_cost is not None and trace_cost > 0:
|
|
694
|
+
set_trace_cost(trace_cost)
|
|
669
695
|
if not isinstance(result, DocumentList): # pyright: ignore[reportUnnecessaryIsInstance]
|
|
670
696
|
raise TypeError(
|
|
671
697
|
f"Flow '{fname}' must return DocumentList, got {type(result).__name__}"
|
ai_pipeline_core/settings.py
CHANGED
|
@@ -94,6 +94,9 @@ class Settings(BaseSettings):
|
|
|
94
94
|
and observability. Optional but recommended
|
|
95
95
|
for production monitoring.
|
|
96
96
|
|
|
97
|
+
lmnr_debug: Debug mode flag for Laminar tracing. Set to "true" to
|
|
98
|
+
enable debug-level traces. Empty string by default.
|
|
99
|
+
|
|
97
100
|
Configuration sources:
|
|
98
101
|
- Environment variables (highest priority)
|
|
99
102
|
- .env file in current directory
|
|
@@ -121,6 +124,7 @@ class Settings(BaseSettings):
|
|
|
121
124
|
|
|
122
125
|
# Observability
|
|
123
126
|
lmnr_project_api_key: str = ""
|
|
127
|
+
lmnr_debug: str = ""
|
|
124
128
|
|
|
125
129
|
|
|
126
130
|
# Legacy: Module-level instance for backwards compatibility
|
|
@@ -35,6 +35,7 @@ Note:
|
|
|
35
35
|
of each document type for consistent organization.
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
|
+
import json
|
|
38
39
|
from pathlib import Path
|
|
39
40
|
from typing import Any, Callable, Sequence, Type
|
|
40
41
|
|
|
@@ -113,9 +114,20 @@ def load_documents_from_directory(
|
|
|
113
114
|
if not file_path.is_file() or file_path.name.endswith(Document.DESCRIPTION_EXTENSION):
|
|
114
115
|
continue
|
|
115
116
|
|
|
117
|
+
# Skip .sources.json files - they are metadata, not documents
|
|
118
|
+
if file_path.name.endswith(".sources.json"):
|
|
119
|
+
continue
|
|
120
|
+
|
|
116
121
|
try:
|
|
117
122
|
content = file_path.read_bytes()
|
|
118
|
-
|
|
123
|
+
|
|
124
|
+
# Load sources if .sources.json exists
|
|
125
|
+
sources = []
|
|
126
|
+
sources_file = file_path.with_name(file_path.name + ".sources.json")
|
|
127
|
+
if sources_file.exists():
|
|
128
|
+
sources = json.loads(sources_file.read_text(encoding="utf-8"))
|
|
129
|
+
|
|
130
|
+
doc = doc_class(name=file_path.name, content=content, sources=sources)
|
|
119
131
|
|
|
120
132
|
desc_file = file_path.with_name(file_path.name + Document.DESCRIPTION_EXTENSION)
|
|
121
133
|
if desc_file.exists():
|
|
@@ -185,6 +197,11 @@ def save_documents_to_directory(base_dir: Path, documents: DocumentList) -> None
|
|
|
185
197
|
desc_file = file_path.with_name(file_path.name + Document.DESCRIPTION_EXTENSION)
|
|
186
198
|
desc_file.write_text(document.description, encoding="utf-8")
|
|
187
199
|
|
|
200
|
+
# Save sources to .sources.json if present
|
|
201
|
+
if document.sources:
|
|
202
|
+
sources_file = file_path.with_name(file_path.name + ".sources.json")
|
|
203
|
+
sources_file.write_text(json.dumps(document.sources, indent=2), encoding="utf-8")
|
|
204
|
+
|
|
188
205
|
|
|
189
206
|
async def run_pipeline(
|
|
190
207
|
flow_func: Callable[..., Any],
|
ai_pipeline_core/tracing.py
CHANGED
|
@@ -15,7 +15,7 @@ import os
|
|
|
15
15
|
from functools import wraps
|
|
16
16
|
from typing import Any, Callable, Literal, ParamSpec, TypeVar, cast, overload
|
|
17
17
|
|
|
18
|
-
from lmnr import Instruments, Laminar, observe
|
|
18
|
+
from lmnr import Attributes, Instruments, Laminar, observe
|
|
19
19
|
from pydantic import BaseModel
|
|
20
20
|
|
|
21
21
|
from ai_pipeline_core.settings import settings
|
|
@@ -356,7 +356,8 @@ def trace(
|
|
|
356
356
|
)
|
|
357
357
|
|
|
358
358
|
# Handle 'debug' level logic - only trace when LMNR_DEBUG is "true"
|
|
359
|
-
|
|
359
|
+
debug_value = settings.lmnr_debug or os.getenv("LMNR_DEBUG", "")
|
|
360
|
+
if level == "debug" and debug_value.lower() != "true":
|
|
360
361
|
return f
|
|
361
362
|
|
|
362
363
|
# --- Pre-computation (done once when the function is decorated) ---
|
|
@@ -369,7 +370,7 @@ def trace(
|
|
|
369
370
|
# Store the new parameters
|
|
370
371
|
_session_id = session_id
|
|
371
372
|
_user_id = user_id
|
|
372
|
-
_metadata = metadata
|
|
373
|
+
_metadata = metadata or {}
|
|
373
374
|
_tags = tags or []
|
|
374
375
|
_span_type = span_type
|
|
375
376
|
_ignore_input = ignore_input
|
|
@@ -403,10 +404,8 @@ def trace(
|
|
|
403
404
|
observe_params["session_id"] = _session_id
|
|
404
405
|
if _user_id:
|
|
405
406
|
observe_params["user_id"] = _user_id
|
|
406
|
-
|
|
407
|
-
# Merge decorator-level metadata and tags
|
|
408
407
|
if _metadata:
|
|
409
|
-
observe_params["metadata"] =
|
|
408
|
+
observe_params["metadata"] = _metadata
|
|
410
409
|
if _tags:
|
|
411
410
|
observe_params["tags"] = observe_params.get("tags", []) + _tags
|
|
412
411
|
if _span_type:
|
|
@@ -472,4 +471,113 @@ def trace(
|
|
|
472
471
|
return decorator # Called as @trace(...)
|
|
473
472
|
|
|
474
473
|
|
|
475
|
-
|
|
474
|
+
def set_trace_cost(cost: float | str) -> None:
|
|
475
|
+
"""Set cost attributes for the current trace span.
|
|
476
|
+
|
|
477
|
+
Sets cost metadata in the current LMNR trace span for tracking expenses
|
|
478
|
+
of custom operations. This function should be called within a traced
|
|
479
|
+
function to dynamically set or update the cost associated with the
|
|
480
|
+
current operation. Particularly useful for tracking costs of external
|
|
481
|
+
API calls, compute resources, or custom billing scenarios.
|
|
482
|
+
|
|
483
|
+
The cost is stored in three metadata fields for compatibility:
|
|
484
|
+
- gen_ai.usage.output_cost: Standard OpenAI cost field
|
|
485
|
+
- gen_ai.usage.cost: Alternative cost field
|
|
486
|
+
- cost: Simple cost field
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
cost: The cost value to set. Can be:
|
|
490
|
+
- float: Cost in dollars (e.g., 0.05 for 5 cents)
|
|
491
|
+
- str: USD format with dollar sign (e.g., "$0.05" or "$1.25")
|
|
492
|
+
Only positive values will be set; zero or negative values are ignored.
|
|
493
|
+
|
|
494
|
+
Example:
|
|
495
|
+
>>> # Track cost of external API call
|
|
496
|
+
>>> @trace
|
|
497
|
+
>>> async def call_translation_api(text: str) -> str:
|
|
498
|
+
... # External API charges per character
|
|
499
|
+
... char_count = len(text)
|
|
500
|
+
... cost_per_char = 0.00001 # $0.00001 per character
|
|
501
|
+
...
|
|
502
|
+
... result = await external_api.translate(text)
|
|
503
|
+
...
|
|
504
|
+
... # Set the cost for this operation
|
|
505
|
+
... set_trace_cost(char_count * cost_per_char)
|
|
506
|
+
... return result
|
|
507
|
+
>>>
|
|
508
|
+
>>> # Track compute resource costs
|
|
509
|
+
>>> @trace
|
|
510
|
+
>>> def process_video(video_path: str) -> dict:
|
|
511
|
+
... duration = get_video_duration(video_path)
|
|
512
|
+
... cost_per_minute = 0.10 # $0.10 per minute
|
|
513
|
+
...
|
|
514
|
+
... result = process_video_content(video_path)
|
|
515
|
+
...
|
|
516
|
+
... # Set cost using string format
|
|
517
|
+
... set_trace_cost(f"${duration * cost_per_minute:.2f}")
|
|
518
|
+
... return result
|
|
519
|
+
>>>
|
|
520
|
+
>>> # Combine with LLM costs in pipeline
|
|
521
|
+
>>> @pipeline_task
|
|
522
|
+
>>> async def enriched_generation(prompt: str) -> str:
|
|
523
|
+
... # LLM cost tracked automatically via ModelResponse
|
|
524
|
+
... response = await llm.generate("gpt-5", messages=prompt)
|
|
525
|
+
...
|
|
526
|
+
... # Add cost for post-processing
|
|
527
|
+
... processing_cost = 0.02 # Fixed cost for enrichment
|
|
528
|
+
... set_trace_cost(processing_cost)
|
|
529
|
+
...
|
|
530
|
+
... return enrich_response(response.content)
|
|
531
|
+
|
|
532
|
+
Raises:
|
|
533
|
+
ValueError: If string format is invalid (not a valid USD amount).
|
|
534
|
+
|
|
535
|
+
Note:
|
|
536
|
+
- This function only works within a traced context (function decorated
|
|
537
|
+
with @trace, @pipeline_task, or @pipeline_flow)
|
|
538
|
+
- LLM costs are tracked automatically via ModelResponse; use this for non-LLM costs
|
|
539
|
+
- Cost should be a positive number representing actual monetary cost in USD
|
|
540
|
+
- The cost is added to the current span's attributes/metadata
|
|
541
|
+
- Multiple calls overwrite the previous cost (not cumulative)
|
|
542
|
+
- If called outside a traced context (no active span), it has no effect
|
|
543
|
+
and does not raise an error
|
|
544
|
+
|
|
545
|
+
See Also:
|
|
546
|
+
- trace: Decorator for adding tracing to functions
|
|
547
|
+
- ModelResponse.get_laminar_metadata: Access LLM generation costs
|
|
548
|
+
- pipeline_task: Task decorator with built-in tracing and optional trace_cost parameter
|
|
549
|
+
- pipeline_flow: Flow decorator with built-in tracing and optional trace_cost parameter
|
|
550
|
+
"""
|
|
551
|
+
# Parse string format if provided
|
|
552
|
+
if isinstance(cost, str):
|
|
553
|
+
# Remove dollar sign and any whitespace
|
|
554
|
+
cost_str = cost.strip()
|
|
555
|
+
if not cost_str.startswith("$"):
|
|
556
|
+
raise ValueError(f"Invalid USD format: {cost!r}. Must start with '$' (e.g., '$0.50')")
|
|
557
|
+
|
|
558
|
+
try:
|
|
559
|
+
# Remove $ and convert to float
|
|
560
|
+
cost_value = float(cost_str[1:])
|
|
561
|
+
except ValueError as e:
|
|
562
|
+
raise ValueError(
|
|
563
|
+
f"Invalid USD format: {cost!r}. Must be a valid number after '$'"
|
|
564
|
+
) from e
|
|
565
|
+
else:
|
|
566
|
+
cost_value = cost
|
|
567
|
+
|
|
568
|
+
if cost_value > 0:
|
|
569
|
+
# Build the attributes dictionary with cost metadata
|
|
570
|
+
attributes: dict[Attributes | str, float] = {
|
|
571
|
+
"gen_ai.usage.output_cost": cost_value,
|
|
572
|
+
"gen_ai.usage.cost": cost_value,
|
|
573
|
+
"cost": cost_value,
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
try:
|
|
577
|
+
Laminar.set_span_attributes(attributes)
|
|
578
|
+
except Exception:
|
|
579
|
+
# Silently ignore if not in a traced context
|
|
580
|
+
pass
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
__all__ = ["trace", "TraceLevel", "TraceInfo", "set_trace_cost"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-pipeline-core
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
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
|
|
@@ -57,11 +57,11 @@ AI Pipeline Core is a production-ready framework that combines document processi
|
|
|
57
57
|
|
|
58
58
|
### Key Features
|
|
59
59
|
|
|
60
|
-
- **Document Processing**: Type-safe handling of text, JSON, YAML, PDFs, and images with automatic MIME type detection
|
|
61
|
-
- **LLM Integration**: Unified interface to any model via LiteLLM proxy with
|
|
60
|
+
- **Document Processing**: Type-safe handling of text, JSON, YAML, PDFs, and images with automatic MIME type detection and provenance tracking
|
|
61
|
+
- **LLM Integration**: Unified interface to any model via LiteLLM proxy with configurable context caching
|
|
62
62
|
- **Structured Output**: Type-safe generation with Pydantic model validation
|
|
63
63
|
- **Workflow Orchestration**: Prefect-based flows and tasks with automatic retries
|
|
64
|
-
- **Observability**: Built-in distributed tracing via Laminar (LMNR) for debugging and monitoring
|
|
64
|
+
- **Observability**: Built-in distributed tracing via Laminar (LMNR) with cost tracking for debugging and monitoring
|
|
65
65
|
- **Local Development**: Simple runner for testing pipelines without infrastructure
|
|
66
66
|
|
|
67
67
|
## Installation
|
|
@@ -178,6 +178,19 @@ doc = MyDocument.create(
|
|
|
178
178
|
# Parse back to original type
|
|
179
179
|
data = doc.parse(dict) # Returns {"key": "value"}
|
|
180
180
|
|
|
181
|
+
# Document provenance tracking (new in v0.1.14)
|
|
182
|
+
doc_with_sources = MyDocument.create(
|
|
183
|
+
name="derived.json",
|
|
184
|
+
content={"result": "processed"},
|
|
185
|
+
sources=[source_doc.sha256, "https://api.example.com/data"]
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Check provenance
|
|
189
|
+
for hash in doc_with_sources.get_source_documents():
|
|
190
|
+
print(f"Derived from document: {hash}")
|
|
191
|
+
for ref in doc_with_sources.get_source_references():
|
|
192
|
+
print(f"External source: {ref}")
|
|
193
|
+
|
|
181
194
|
# Temporary documents (never persisted)
|
|
182
195
|
temp = TemporaryDocument.create(
|
|
183
196
|
name="api_response.json",
|
|
@@ -211,6 +224,10 @@ if doc.is_text:
|
|
|
211
224
|
|
|
212
225
|
# Parse structured data
|
|
213
226
|
data = doc.as_json() # or as_yaml(), as_pydantic_model()
|
|
227
|
+
|
|
228
|
+
# Enhanced filtering (new in v0.1.14)
|
|
229
|
+
filtered = documents.filter_by([Doc1, Doc2, Doc3]) # Multiple types
|
|
230
|
+
named = documents.filter_by(["file1.txt", "file2.txt"]) # Multiple names
|
|
214
231
|
```
|
|
215
232
|
|
|
216
233
|
### LLM Integration
|
|
@@ -233,7 +250,7 @@ static_context = AIMessages([large_document])
|
|
|
233
250
|
# First call: caches context
|
|
234
251
|
r1 = await llm.generate(
|
|
235
252
|
model="gpt-5",
|
|
236
|
-
context=static_context, # Cached for 120 seconds
|
|
253
|
+
context=static_context, # Cached for 120 seconds by default
|
|
237
254
|
messages="Summarize" # Dynamic query
|
|
238
255
|
)
|
|
239
256
|
|
|
@@ -243,6 +260,22 @@ r2 = await llm.generate(
|
|
|
243
260
|
context=static_context, # Reused from cache!
|
|
244
261
|
messages="Key points?" # Different query
|
|
245
262
|
)
|
|
263
|
+
|
|
264
|
+
# Custom cache TTL (new in v0.1.14)
|
|
265
|
+
response = await llm.generate(
|
|
266
|
+
model="gpt-5",
|
|
267
|
+
context=static_context,
|
|
268
|
+
messages="Analyze",
|
|
269
|
+
options=ModelOptions(cache_ttl="300s") # Cache for 5 minutes
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Disable caching for dynamic contexts
|
|
273
|
+
response = await llm.generate(
|
|
274
|
+
model="gpt-5",
|
|
275
|
+
context=dynamic_context,
|
|
276
|
+
messages="Process",
|
|
277
|
+
options=ModelOptions(cache_ttl=None) # No caching
|
|
278
|
+
)
|
|
246
279
|
```
|
|
247
280
|
|
|
248
281
|
### Flow Configuration
|
|
@@ -272,11 +305,13 @@ class ProcessingConfig(FlowConfig):
|
|
|
272
305
|
Enhanced decorators with built-in tracing and monitoring:
|
|
273
306
|
|
|
274
307
|
```python
|
|
275
|
-
from ai_pipeline_core import pipeline_flow, pipeline_task
|
|
308
|
+
from ai_pipeline_core import pipeline_flow, pipeline_task, set_trace_cost
|
|
276
309
|
|
|
277
310
|
@pipeline_task # Automatic retry, tracing, and monitoring
|
|
278
311
|
async def process_chunk(data: str) -> str:
|
|
279
|
-
|
|
312
|
+
result = await transform(data)
|
|
313
|
+
set_trace_cost(0.05) # Track costs (new in v0.1.14)
|
|
314
|
+
return result
|
|
280
315
|
|
|
281
316
|
@pipeline_flow # Full observability and orchestration
|
|
282
317
|
async def main_flow(
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
ai_pipeline_core/__init__.py,sha256=jDITXj2wA7lQ46IT9TOvmjg7Ug2aY_QPkuLYfYQEd2E,5484
|
|
2
|
+
ai_pipeline_core/exceptions.py,sha256=vx-XLTw2fJSPs-vwtXVYtqoQUcOc0JeI7UmHqRqQYWU,1569
|
|
3
|
+
ai_pipeline_core/pipeline.py,sha256=dq-v4IYEaBNt290y545E5JuUahe_k3ffI2_rrGjD-GQ,29384
|
|
4
|
+
ai_pipeline_core/prefect.py,sha256=CC8qeIpVqzNq8m6YWNIcRYeDEqkcAFiNjFwcuwwKO0k,2064
|
|
5
|
+
ai_pipeline_core/prompt_manager.py,sha256=XZwah5fp3GyZ0e0na_yOs6m4ngCcotysh-K_cU2U978,11572
|
|
6
|
+
ai_pipeline_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
ai_pipeline_core/settings.py,sha256=X8m13zUHWte953l3or45wG8o7ZQ4X-XBe6umk4PlkMQ,4598
|
|
8
|
+
ai_pipeline_core/tracing.py,sha256=uXQdP7GIvTghiqyG3XIgES_DbWfkxU0guSqfiazkc0Q,22877
|
|
9
|
+
ai_pipeline_core/documents/__init__.py,sha256=WHStvGZiSyybOcMTYxSV24U6MA3Am_0_Az5p-DuMFrk,738
|
|
10
|
+
ai_pipeline_core/documents/document.py,sha256=2UfLx4t7k0lV1v2R67mykeEwRAuyAPOCCjvfUOmPDiI,60450
|
|
11
|
+
ai_pipeline_core/documents/document_list.py,sha256=SnWzRqCloI8A6e1HIxaKKbaSkPbL2RrqtkjQKY8H6dI,11354
|
|
12
|
+
ai_pipeline_core/documents/flow_document.py,sha256=GbOa8mjo6xy5t6EUY7E857S0q5nFBgC1yYQdD7gr-Ls,4043
|
|
13
|
+
ai_pipeline_core/documents/mime_type.py,sha256=DkW88K95el5nAmhC00XLS0G3WpDXgs5IRsBWbKiqG3Y,7995
|
|
14
|
+
ai_pipeline_core/documents/task_document.py,sha256=h2jAE3k9-2MJ_MjDrH8UtJRXxNuoxACWBfHu2xEHsN4,4226
|
|
15
|
+
ai_pipeline_core/documents/temporary_document.py,sha256=1Jpi5ozEes4nudilptnXyXatImZDNAhGL7Jd3cQXM3g,2845
|
|
16
|
+
ai_pipeline_core/documents/utils.py,sha256=ZyJNjFN7ihWno0K7dJZed7twYmmPLA0z40UzFw1A3A8,5465
|
|
17
|
+
ai_pipeline_core/flow/__init__.py,sha256=2BfWYMOPYW5teGzwo-qzpn_bom1lxxry0bPsjVgcsCk,188
|
|
18
|
+
ai_pipeline_core/flow/config.py,sha256=4JVc30tztSW9sYufWLN3hx6qSeR1VX31H1aI9I2jIrA,12114
|
|
19
|
+
ai_pipeline_core/flow/options.py,sha256=2rKR2GifhXcyw8avI_oiEDMLC2jm5Qzpw8z56pbxUMo,2285
|
|
20
|
+
ai_pipeline_core/llm/__init__.py,sha256=kLMoOj_JQgvGZXZXU-5u9QzLAu2sq5ixMCyEqk2jKKc,857
|
|
21
|
+
ai_pipeline_core/llm/ai_messages.py,sha256=udzFwUFfQgJeu1JzpqVuBr0QHdWXvuhfJEEgedSHauY,8383
|
|
22
|
+
ai_pipeline_core/llm/client.py,sha256=PZkNaBe1x20ecPTI30PjUjuo26vB76Tam422X3bWhzk,19454
|
|
23
|
+
ai_pipeline_core/llm/model_options.py,sha256=_wAUM3d7b_1oBeSpDjcyyx_wZmvBMobGOyF0JEgLTPg,7660
|
|
24
|
+
ai_pipeline_core/llm/model_response.py,sha256=TUgEi8CLQ1Bw3vvQeNzX3j9YYjuToNZseaMJ7Uaf4GI,15224
|
|
25
|
+
ai_pipeline_core/llm/model_types.py,sha256=JjaJSDY3TTL-ifSLKVNBEV1KJtBIJTr1QwIh9ZnD-is,2895
|
|
26
|
+
ai_pipeline_core/logging/__init__.py,sha256=4iXN4jNiOXLfCYGH3wZB0-Zf-SlU-gQ07f1AyP2H5-s,660
|
|
27
|
+
ai_pipeline_core/logging/logging.yml,sha256=YTW48keO_K5bkkb-KXGM7ZuaYKiquLsjsURei8Ql0V4,1353
|
|
28
|
+
ai_pipeline_core/logging/logging_config.py,sha256=QYI-vz9BqNA02RxoIWPdKhomZpZJkXeFINIuu08O3hY,6242
|
|
29
|
+
ai_pipeline_core/logging/logging_mixin.py,sha256=UFd_CfyJ6YP_XVA-CrpAszOr8g1FH8RwRIwiY23kRG0,8131
|
|
30
|
+
ai_pipeline_core/simple_runner/__init__.py,sha256=OXKFOu3rRcqXCWwBBxnZ7Vz8KRFF5g-G3eJq-vm3CUY,521
|
|
31
|
+
ai_pipeline_core/simple_runner/cli.py,sha256=sbIvv_d401o8h-b5JlcIJQhwzte1sttdmUi2a3As-wY,9357
|
|
32
|
+
ai_pipeline_core/simple_runner/simple_runner.py,sha256=1FC1x0WlOUbOiMbiOtkDQdY0d5NswDbx0FSzrNmewCA,15067
|
|
33
|
+
ai_pipeline_core-0.1.14.dist-info/METADATA,sha256=vzEIlKku7IF-tY0ho30lP8yMaFBWHOASlLa7CaQRsjw,14351
|
|
34
|
+
ai_pipeline_core-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
35
|
+
ai_pipeline_core-0.1.14.dist-info/licenses/LICENSE,sha256=kKj8mfbdWwkyG3U6n7ztB3bAZlEwShTkAsvaY657i3I,1074
|
|
36
|
+
ai_pipeline_core-0.1.14.dist-info/RECORD,,
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
ai_pipeline_core/__init__.py,sha256=woPhgoXf2GlKkWqvzBmf57ODLMsmsoInB0nimFrsuzE,5396
|
|
2
|
-
ai_pipeline_core/exceptions.py,sha256=vx-XLTw2fJSPs-vwtXVYtqoQUcOc0JeI7UmHqRqQYWU,1569
|
|
3
|
-
ai_pipeline_core/pipeline.py,sha256=EETCEoKkFcVvsQqtVIV5S5DrVII4XPSuCnqF7zA2_jc,28137
|
|
4
|
-
ai_pipeline_core/prefect.py,sha256=CC8qeIpVqzNq8m6YWNIcRYeDEqkcAFiNjFwcuwwKO0k,2064
|
|
5
|
-
ai_pipeline_core/prompt_manager.py,sha256=XZwah5fp3GyZ0e0na_yOs6m4ngCcotysh-K_cU2U978,11572
|
|
6
|
-
ai_pipeline_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
ai_pipeline_core/settings.py,sha256=XfIw-UOuelSiPAYCd3VmOhsGmAxsCy9IsxWPWAf0wGY,4427
|
|
8
|
-
ai_pipeline_core/tracing.py,sha256=75wKL__0arY54dnDcG3F-4KC6mDXg6lMA219-fpxhjI,18348
|
|
9
|
-
ai_pipeline_core/documents/__init__.py,sha256=FOYBUKipW_uuzFieW3MigvNLEpbCI1jeY9_0VxJsoS0,692
|
|
10
|
-
ai_pipeline_core/documents/document.py,sha256=tDUBootN_hK75k3XASyBxt-ZqtZuynTwgcL_L5ZWN1Q,51521
|
|
11
|
-
ai_pipeline_core/documents/document_list.py,sha256=m8ei2jLTHt47uCKHmn8BuMMbfwPIKH5g9oPO1jvIPmg,8282
|
|
12
|
-
ai_pipeline_core/documents/flow_document.py,sha256=bJxLjvUE6xfR5-JCy1oi7XtZOwLBOSuUBBJjRaQk6TI,4748
|
|
13
|
-
ai_pipeline_core/documents/mime_type.py,sha256=DkW88K95el5nAmhC00XLS0G3WpDXgs5IRsBWbKiqG3Y,7995
|
|
14
|
-
ai_pipeline_core/documents/task_document.py,sha256=HonlS7hO6zisu67JFXu6LjGLyc7BuylUHuP7SMcHCY4,4910
|
|
15
|
-
ai_pipeline_core/documents/temporary_document.py,sha256=cMuNLnRlWrMryzfZXOIrTrZ2blsxjmflnL8O3zicWIk,3240
|
|
16
|
-
ai_pipeline_core/documents/utils.py,sha256=VHq1gAWTMmJNS55HSZ2--sDErE4DVtFsxrv6y2KXmdk,3472
|
|
17
|
-
ai_pipeline_core/flow/__init__.py,sha256=2BfWYMOPYW5teGzwo-qzpn_bom1lxxry0bPsjVgcsCk,188
|
|
18
|
-
ai_pipeline_core/flow/config.py,sha256=4JVc30tztSW9sYufWLN3hx6qSeR1VX31H1aI9I2jIrA,12114
|
|
19
|
-
ai_pipeline_core/flow/options.py,sha256=UiddkxWrXAhsFtOOt06JhttTp-0gejc8kG0K8Falg1c,2297
|
|
20
|
-
ai_pipeline_core/llm/__init__.py,sha256=QWhMVs4OLTgIvOHfxb7AQhpfCXlgGpoGiJ8PSbVyzZs,661
|
|
21
|
-
ai_pipeline_core/llm/ai_messages.py,sha256=YS3tfqivj9kS6sYsDAgw9LHEjg9cKS1SAHviCzkvAos,8492
|
|
22
|
-
ai_pipeline_core/llm/client.py,sha256=8n1AzDLQMzGjLb-kZ3OTdNa4-648M7GhVJfPPx7sjwU,18194
|
|
23
|
-
ai_pipeline_core/llm/model_options.py,sha256=HX3yI9JPCtjR3LIS--Ku9R4YPTfUkqp1kSsMenQejxs,6923
|
|
24
|
-
ai_pipeline_core/llm/model_response.py,sha256=IkNXl7AsEPrHIAhsOncpZ52bkOfLp6e3EaXqdf0LtLI,12701
|
|
25
|
-
ai_pipeline_core/llm/model_types.py,sha256=Jv2h8oMhIDEBTulWbkmhVS4aiMI39Mzlhk_xOlkCQXo,2829
|
|
26
|
-
ai_pipeline_core/logging/__init__.py,sha256=4iXN4jNiOXLfCYGH3wZB0-Zf-SlU-gQ07f1AyP2H5-s,660
|
|
27
|
-
ai_pipeline_core/logging/logging.yml,sha256=YTW48keO_K5bkkb-KXGM7ZuaYKiquLsjsURei8Ql0V4,1353
|
|
28
|
-
ai_pipeline_core/logging/logging_config.py,sha256=QYI-vz9BqNA02RxoIWPdKhomZpZJkXeFINIuu08O3hY,6242
|
|
29
|
-
ai_pipeline_core/logging/logging_mixin.py,sha256=UFd_CfyJ6YP_XVA-CrpAszOr8g1FH8RwRIwiY23kRG0,8131
|
|
30
|
-
ai_pipeline_core/simple_runner/__init__.py,sha256=OXKFOu3rRcqXCWwBBxnZ7Vz8KRFF5g-G3eJq-vm3CUY,521
|
|
31
|
-
ai_pipeline_core/simple_runner/cli.py,sha256=sbIvv_d401o8h-b5JlcIJQhwzte1sttdmUi2a3As-wY,9357
|
|
32
|
-
ai_pipeline_core/simple_runner/simple_runner.py,sha256=Q7PRAgf_VUPS72WV9pER9WT0AQo9r4WbRclsRXXJiW4,14329
|
|
33
|
-
ai_pipeline_core-0.1.12.dist-info/METADATA,sha256=ytaOH7I8CR_jRrRvvZW8HDldFdFw8mT8gYC5G-X-NRA,13192
|
|
34
|
-
ai_pipeline_core-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
35
|
-
ai_pipeline_core-0.1.12.dist-info/licenses/LICENSE,sha256=kKj8mfbdWwkyG3U6n7ztB3bAZlEwShTkAsvaY657i3I,1074
|
|
36
|
-
ai_pipeline_core-0.1.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|