diff --git a/.blackboxrules b/.blackboxrules index 6125caa..af4572e 100644 --- a/.blackboxrules +++ b/.blackboxrules @@ -23,10 +23,10 @@ A pipeline file has three main sections: #### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. #### Concept Definitions @@ -62,7 +62,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ### Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -471,7 +471,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -480,7 +480,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -588,15 +588,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -#### Key Parameters +#### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -604,9 +605,143 @@ For more control, you can use a nested `template` section instead of the `templa #### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +#### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +##### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +##### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ### PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. @@ -952,13 +1087,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -## Here we have a single input and it's a PDF. -## Because PDFContent is a native concept, we can use it directly as a value, +## Here we have a single input and it's a document. +## Because DocumentContent is a native concept, we can use it directly as a value, ## the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) @@ -1081,82 +1216,4 @@ result_list = pipe_output.main_stuff_as_items(item_type=GanttChart) ``` --- - -## Rules to choose LLM models used in PipeLLMs. - -### LLM Configuration System - -In order to use it in a pipe, an LLM is referenced by its llm_handle (alias) and possibly by an llm_preset. -LLM configurations are managed through the new inference backend system with files located in `.pipelex/inference/`: - -- **Model Deck**: `.pipelex/inference/deck/base_deck.toml` and `.pipelex/inference/deck/overrides.toml` -- **Backends**: `.pipelex/inference/backends.toml` and `.pipelex/inference/backends/*.toml` -- **Routing**: `.pipelex/inference/routing_profiles.toml` - -### LLM Handles - -An llm_handle can be either: -1. **A direct model name** (like "gpt-4o-mini", "claude-3-sonnet") - automatically available for all models loaded by the inference backend system -2. **An alias** - user-defined shortcuts that map to model names, defined in the `[aliases]` section: - -```toml -[aliases] -base-claude = "claude-4.5-sonnet" -base-gpt = "gpt-5" -base-gemini = "gemini-2.5-flash" -base-mistral = "mistral-medium" -``` - -The system first looks for direct model names, then checks aliases if no direct match is found. The system handles model routing through backends automatically. - -### Using an LLM Handle in a PipeLLM - -Here is an example of using an llm_handle to specify which LLM to use in a PipeLLM: - -```plx -[pipe.hello_world] -type = "PipeLLM" -description = "Write text about Hello World." -output = "Text" -model = { model = "gpt-5", temperature = 0.9 } -prompt = """ -Write a haiku about Hello World. -""" -``` - -As you can see, to use the LLM, you must also indicate the temperature (float between 0 and 1) and max_tokens (either an int or the string "auto"). - -### LLM Presets - -Presets are meant to record the choice of an llm with its hyper parameters (temperature and max_tokens) if it's good for a particular task. LLM Presets are skill-oriented. - -Examples: -```toml -llm_to_engineer = { model = "base-claude", temperature = 1 } -llm_to_extract_invoice = { model = "claude-4.5-sonnet", temperature = 0.1, max_tokens = "auto" } -``` - -The interest is that these presets can be used to set the LLM choice in a PipeLLM, like this: - -```plx -[pipe.extract_invoice] -type = "PipeLLM" -description = "Extract invoice information from an invoice text transcript" -inputs = { invoice_text = "InvoiceText" } -output = "Invoice" -model = "llm_to_extract_invoice" -prompt = """ -Extract invoice information from this invoice: - -The category of this invoice is: $invoice_details.category. - -@invoice_text -""" -``` - -The setting here `model = "llm_to_extract_invoice"` works because "llm_to_extract_invoice" has been declared as an llm_preset in the deck. -You must not use an LLM preset in a PipeLLM that does not exist in the deck. If needed, you can add llm presets. - - -You can override the predefined llm presets by setting them in `.pipelex/inference/deck/overrides.toml`. diff --git a/.cursor/rules/run_pipelex.mdc b/.cursor/rules/run_pipelex.mdc index 8387838..7650051 100644 --- a/.cursor/rules/run_pipelex.mdc +++ b/.cursor/rules/run_pipelex.mdc @@ -99,13 +99,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -# Here we have a single input and it's a PDF. -# Because PDFContent is a native concept, we can use it directly as a value, +# Here we have a single input and it's a document. +# Because DocumentContent is a native concept, we can use it directly as a value, # the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) diff --git a/.cursor/rules/write_pipelex.mdc b/.cursor/rules/write_pipelex.mdc index 9f23faf..93422cc 100644 --- a/.cursor/rules/write_pipelex.mdc +++ b/.cursor/rules/write_pipelex.mdc @@ -27,10 +27,10 @@ A pipeline file has three main sections: ### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. ### Concept Definitions @@ -66,7 +66,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ## Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -475,7 +475,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -484,7 +484,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -592,15 +592,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -### Key Parameters +### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -608,9 +609,143 @@ For more control, you can use a nested `template` section instead of the `templa ### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +#### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +#### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +#### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +#### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ## PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. diff --git a/.env.example b/.env.example index 22b29d7..cbc7ad2 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -PIPELEX_INFERENCE_API_KEY= \ No newline at end of file +PIPELEX_GATEWAY_API_KEY= \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6125caa..af4572e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -23,10 +23,10 @@ A pipeline file has three main sections: #### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. #### Concept Definitions @@ -62,7 +62,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ### Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -471,7 +471,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -480,7 +480,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -588,15 +588,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -#### Key Parameters +#### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -604,9 +605,143 @@ For more control, you can use a nested `template` section instead of the `templa #### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +#### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +##### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +##### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ### PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. @@ -952,13 +1087,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -## Here we have a single input and it's a PDF. -## Because PDFContent is a native concept, we can use it directly as a value, +## Here we have a single input and it's a document. +## Because DocumentContent is a native concept, we can use it directly as a value, ## the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) @@ -1081,82 +1216,4 @@ result_list = pipe_output.main_stuff_as_items(item_type=GanttChart) ``` --- - -## Rules to choose LLM models used in PipeLLMs. - -### LLM Configuration System - -In order to use it in a pipe, an LLM is referenced by its llm_handle (alias) and possibly by an llm_preset. -LLM configurations are managed through the new inference backend system with files located in `.pipelex/inference/`: - -- **Model Deck**: `.pipelex/inference/deck/base_deck.toml` and `.pipelex/inference/deck/overrides.toml` -- **Backends**: `.pipelex/inference/backends.toml` and `.pipelex/inference/backends/*.toml` -- **Routing**: `.pipelex/inference/routing_profiles.toml` - -### LLM Handles - -An llm_handle can be either: -1. **A direct model name** (like "gpt-4o-mini", "claude-3-sonnet") - automatically available for all models loaded by the inference backend system -2. **An alias** - user-defined shortcuts that map to model names, defined in the `[aliases]` section: - -```toml -[aliases] -base-claude = "claude-4.5-sonnet" -base-gpt = "gpt-5" -base-gemini = "gemini-2.5-flash" -base-mistral = "mistral-medium" -``` - -The system first looks for direct model names, then checks aliases if no direct match is found. The system handles model routing through backends automatically. - -### Using an LLM Handle in a PipeLLM - -Here is an example of using an llm_handle to specify which LLM to use in a PipeLLM: - -```plx -[pipe.hello_world] -type = "PipeLLM" -description = "Write text about Hello World." -output = "Text" -model = { model = "gpt-5", temperature = 0.9 } -prompt = """ -Write a haiku about Hello World. -""" -``` - -As you can see, to use the LLM, you must also indicate the temperature (float between 0 and 1) and max_tokens (either an int or the string "auto"). - -### LLM Presets - -Presets are meant to record the choice of an llm with its hyper parameters (temperature and max_tokens) if it's good for a particular task. LLM Presets are skill-oriented. - -Examples: -```toml -llm_to_engineer = { model = "base-claude", temperature = 1 } -llm_to_extract_invoice = { model = "claude-4.5-sonnet", temperature = 0.1, max_tokens = "auto" } -``` - -The interest is that these presets can be used to set the LLM choice in a PipeLLM, like this: - -```plx -[pipe.extract_invoice] -type = "PipeLLM" -description = "Extract invoice information from an invoice text transcript" -inputs = { invoice_text = "InvoiceText" } -output = "Invoice" -model = "llm_to_extract_invoice" -prompt = """ -Extract invoice information from this invoice: - -The category of this invoice is: $invoice_details.category. - -@invoice_text -""" -``` - -The setting here `model = "llm_to_extract_invoice"` works because "llm_to_extract_invoice" has been declared as an llm_preset in the deck. -You must not use an LLM preset in a PipeLLM that does not exist in the deck. If needed, you can add llm presets. - - -You can override the predefined llm presets by setting them in `.pipelex/inference/deck/overrides.toml`. diff --git a/.github/workflows/tests-check.yml b/.github/workflows/tests-check.yml index c94ad16..a347c29 100644 --- a/.github/workflows/tests-check.yml +++ b/.github/workflows/tests-check.yml @@ -43,8 +43,5 @@ jobs: source .venv/bin/activate echo -e "y\nA\n1" |pipelex init - - name: Boot test - run: make tp TEST=TestFundamentals - - name: Run tests run: make gha-tests diff --git a/.gitignore b/.gitignore index 29670a3..443da68 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,9 @@ dist/ # Results results/ -# temps temp/ pipelex_super.toml +pipelex_override.toml +telemetry_override.toml base_llm_deck.toml +.pipelex/storage diff --git a/.vscode/settings.json b/.vscode/settings.json index e908f73..acd31dc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,6 @@ "mypy.runUsingActiveInterpreter": true, "search.exclude": { ".mypy_cache/*": true, - "**/dev_context": true }, "files.exclude": { "**/__pycache__": true, diff --git a/.windsurfrules.md b/.windsurfrules.md index 6125caa..af4572e 100644 --- a/.windsurfrules.md +++ b/.windsurfrules.md @@ -23,10 +23,10 @@ A pipeline file has three main sections: #### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. #### Concept Definitions @@ -62,7 +62,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ### Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -471,7 +471,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -480,7 +480,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -588,15 +588,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -#### Key Parameters +#### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -604,9 +605,143 @@ For more control, you can use a nested `template` section instead of the `templa #### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +#### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +##### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +##### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ### PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. @@ -952,13 +1087,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -## Here we have a single input and it's a PDF. -## Because PDFContent is a native concept, we can use it directly as a value, +## Here we have a single input and it's a document. +## Because DocumentContent is a native concept, we can use it directly as a value, ## the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) @@ -1081,82 +1216,4 @@ result_list = pipe_output.main_stuff_as_items(item_type=GanttChart) ``` --- - -## Rules to choose LLM models used in PipeLLMs. - -### LLM Configuration System - -In order to use it in a pipe, an LLM is referenced by its llm_handle (alias) and possibly by an llm_preset. -LLM configurations are managed through the new inference backend system with files located in `.pipelex/inference/`: - -- **Model Deck**: `.pipelex/inference/deck/base_deck.toml` and `.pipelex/inference/deck/overrides.toml` -- **Backends**: `.pipelex/inference/backends.toml` and `.pipelex/inference/backends/*.toml` -- **Routing**: `.pipelex/inference/routing_profiles.toml` - -### LLM Handles - -An llm_handle can be either: -1. **A direct model name** (like "gpt-4o-mini", "claude-3-sonnet") - automatically available for all models loaded by the inference backend system -2. **An alias** - user-defined shortcuts that map to model names, defined in the `[aliases]` section: - -```toml -[aliases] -base-claude = "claude-4.5-sonnet" -base-gpt = "gpt-5" -base-gemini = "gemini-2.5-flash" -base-mistral = "mistral-medium" -``` - -The system first looks for direct model names, then checks aliases if no direct match is found. The system handles model routing through backends automatically. - -### Using an LLM Handle in a PipeLLM - -Here is an example of using an llm_handle to specify which LLM to use in a PipeLLM: - -```plx -[pipe.hello_world] -type = "PipeLLM" -description = "Write text about Hello World." -output = "Text" -model = { model = "gpt-5", temperature = 0.9 } -prompt = """ -Write a haiku about Hello World. -""" -``` - -As you can see, to use the LLM, you must also indicate the temperature (float between 0 and 1) and max_tokens (either an int or the string "auto"). - -### LLM Presets - -Presets are meant to record the choice of an llm with its hyper parameters (temperature and max_tokens) if it's good for a particular task. LLM Presets are skill-oriented. - -Examples: -```toml -llm_to_engineer = { model = "base-claude", temperature = 1 } -llm_to_extract_invoice = { model = "claude-4.5-sonnet", temperature = 0.1, max_tokens = "auto" } -``` - -The interest is that these presets can be used to set the LLM choice in a PipeLLM, like this: - -```plx -[pipe.extract_invoice] -type = "PipeLLM" -description = "Extract invoice information from an invoice text transcript" -inputs = { invoice_text = "InvoiceText" } -output = "Invoice" -model = "llm_to_extract_invoice" -prompt = """ -Extract invoice information from this invoice: - -The category of this invoice is: $invoice_details.category. - -@invoice_text -""" -``` - -The setting here `model = "llm_to_extract_invoice"` works because "llm_to_extract_invoice" has been declared as an llm_preset in the deck. -You must not use an LLM preset in a PipeLLM that does not exist in the deck. If needed, you can add llm presets. - - -You can override the predefined llm presets by setting them in `.pipelex/inference/deck/overrides.toml`. diff --git a/AGENTS.md b/AGENTS.md index 6125caa..af4572e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,10 +23,10 @@ A pipeline file has three main sections: #### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. #### Concept Definitions @@ -62,7 +62,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ### Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -471,7 +471,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -480,7 +480,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -588,15 +588,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -#### Key Parameters +#### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -604,9 +605,143 @@ For more control, you can use a nested `template` section instead of the `templa #### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +#### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +##### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +##### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ### PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. @@ -952,13 +1087,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -## Here we have a single input and it's a PDF. -## Because PDFContent is a native concept, we can use it directly as a value, +## Here we have a single input and it's a document. +## Because DocumentContent is a native concept, we can use it directly as a value, ## the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) @@ -1081,82 +1216,4 @@ result_list = pipe_output.main_stuff_as_items(item_type=GanttChart) ``` --- - -## Rules to choose LLM models used in PipeLLMs. - -### LLM Configuration System - -In order to use it in a pipe, an LLM is referenced by its llm_handle (alias) and possibly by an llm_preset. -LLM configurations are managed through the new inference backend system with files located in `.pipelex/inference/`: - -- **Model Deck**: `.pipelex/inference/deck/base_deck.toml` and `.pipelex/inference/deck/overrides.toml` -- **Backends**: `.pipelex/inference/backends.toml` and `.pipelex/inference/backends/*.toml` -- **Routing**: `.pipelex/inference/routing_profiles.toml` - -### LLM Handles - -An llm_handle can be either: -1. **A direct model name** (like "gpt-4o-mini", "claude-3-sonnet") - automatically available for all models loaded by the inference backend system -2. **An alias** - user-defined shortcuts that map to model names, defined in the `[aliases]` section: - -```toml -[aliases] -base-claude = "claude-4.5-sonnet" -base-gpt = "gpt-5" -base-gemini = "gemini-2.5-flash" -base-mistral = "mistral-medium" -``` - -The system first looks for direct model names, then checks aliases if no direct match is found. The system handles model routing through backends automatically. - -### Using an LLM Handle in a PipeLLM - -Here is an example of using an llm_handle to specify which LLM to use in a PipeLLM: - -```plx -[pipe.hello_world] -type = "PipeLLM" -description = "Write text about Hello World." -output = "Text" -model = { model = "gpt-5", temperature = 0.9 } -prompt = """ -Write a haiku about Hello World. -""" -``` - -As you can see, to use the LLM, you must also indicate the temperature (float between 0 and 1) and max_tokens (either an int or the string "auto"). - -### LLM Presets - -Presets are meant to record the choice of an llm with its hyper parameters (temperature and max_tokens) if it's good for a particular task. LLM Presets are skill-oriented. - -Examples: -```toml -llm_to_engineer = { model = "base-claude", temperature = 1 } -llm_to_extract_invoice = { model = "claude-4.5-sonnet", temperature = 0.1, max_tokens = "auto" } -``` - -The interest is that these presets can be used to set the LLM choice in a PipeLLM, like this: - -```plx -[pipe.extract_invoice] -type = "PipeLLM" -description = "Extract invoice information from an invoice text transcript" -inputs = { invoice_text = "InvoiceText" } -output = "Invoice" -model = "llm_to_extract_invoice" -prompt = """ -Extract invoice information from this invoice: - -The category of this invoice is: $invoice_details.category. - -@invoice_text -""" -``` - -The setting here `model = "llm_to_extract_invoice"` works because "llm_to_extract_invoice" has been declared as an llm_preset in the deck. -You must not use an LLM preset in a PipeLLM that does not exist in the deck. If needed, you can add llm presets. - - -You can override the predefined llm presets by setting them in `.pipelex/inference/deck/overrides.toml`. diff --git a/CLAUDE.md b/CLAUDE.md index 6125caa..af4572e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,10 +23,10 @@ A pipeline file has three main sections: #### Domain Statement ```plx -domain = "domain_name" +domain = "domain_code" description = "Description of the domain" # Optional ``` -Note: The domain name usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. +Note: The domain code usually matches the plx filename for single-file domains. For multi-file domains, use the subdirectory name. #### Concept Definitions @@ -62,7 +62,7 @@ For details on how to structure concepts with fields, see the "Structuring Model ### Pipe Base Definition ```plx -[pipe.your_pipe_name] +[pipe.your_pipe_code] type = "PipeLLM" description = "A description of what your pipe does" inputs = { input_1 = "ConceptName1", input_2 = "ConceptName2" } @@ -471,7 +471,7 @@ The PipeExtract operator is used to extract text and images from an image or a P [pipe.extract_info] type = "PipeExtract" description = "extract the information" -inputs = { document = "PDF" } # or { image = "Image" } if it's an image. This is the only input. +inputs = { document = "Document" } # or { image = "Image" } if it's an image. This is the only input. output = "Page" ``` @@ -480,7 +480,7 @@ Using Extract Model Settings: [pipe.extract_with_model] type = "PipeExtract" description = "Extract with specific model" -inputs = { document = "PDF" } +inputs = { document = "Document" } output = "Page" model = "base_extract_mistral" # Use predefined extract preset or model alias ``` @@ -588,15 +588,16 @@ $sales_rep.phone | $sales_rep.email """ ``` -#### Key Parameters +#### Key Parameters (Template Mode) -- `template`: Inline template string (mutually exclusive with template_name) +- `template`: Inline template string (mutually exclusive with template_name and construct) - `template_name`: Name of a predefined template (mutually exclusive with template) - `template_category`: Template type ("llm_prompt", "html", "markdown", "mermaid", etc.) - `templating_style`: Styling options for template rendering - `extra_context`: Additional context variables for template For more control, you can use a nested `template` section instead of the `template` field: + - `template.template`: The template string - `template.category`: Template type - `template.templating_style`: Styling options @@ -604,9 +605,143 @@ For more control, you can use a nested `template` section instead of the `templa #### Template Variables Use the same variable insertion rules as PipeLLM: + - `@variable` for block insertion (multi-line content) - `$variable` for inline insertion (short text) +#### Construct Mode (for StructuredContent Output) + +PipeCompose can also generate `StructuredContent` objects using the `construct` section. This mode composes field values from fixed values, variable references, templates, or nested structures. + +**When to use construct mode:** + +- You need to output a structured object (not just Text) +- You want to deterministically compose fields from existing data +- No LLM is needed - just data composition and templating + +##### Basic Construct Usage + +```plx +[concept.SalesSummary] +description = "A structured sales summary" + +[concept.SalesSummary.structure] +report_title = { type = "text", description = "Title of the report" } +customer_name = { type = "text", description = "Customer name" } +deal_value = { type = "number", description = "Deal value" } +summary_text = { type = "text", description = "Generated summary text" } + +[pipe.compose_summary] +type = "PipeCompose" +description = "Compose a sales summary from deal data" +inputs = { deal = "Deal" } +output = "SalesSummary" + +[pipe.compose_summary.construct] +report_title = "Monthly Sales Report" +customer_name = { from = "deal.customer_name" } +deal_value = { from = "deal.amount" } +summary_text = { template = "Deal worth $deal.amount with $deal.customer_name" } +``` + +##### Field Composition Methods + +There are four ways to define field values in a construct: + +**1. Fixed Value (literal)** + +Use a literal value directly: + +```plx +[pipe.compose_report.construct] +report_title = "Annual Report" +report_year = 2024 +is_draft = false +``` + +**2. Variable Reference (`from`)** + +Get a value from working memory using a dotted path: + +```plx +[pipe.compose_report.construct] +customer_name = { from = "deal.customer_name" } +total_amount = { from = "order.total" } +street_address = { from = "customer.address.street" } +``` + +**3. Template (`template`)** + +Render a Jinja2 template with variable substitution: + +```plx +[pipe.compose_report.construct] +invoice_number = { template = "INV-$order.id" } +summary = { template = "Deal worth $deal.amount with $deal.customer_name on {{ current_date }}" } +``` + +**4. Nested Construct** + +For nested structures, use a TOML subsection: + +```plx +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Complete Construct Example + +```plx +domain = "invoicing" + +[concept.Address] +description = "A postal address" + +[concept.Address.structure] +street = { type = "text", description = "Street address" } +city = { type = "text", description = "City name" } +country = { type = "text", description = "Country name" } + +[concept.Invoice] +description = "An invoice document" + +[concept.Invoice.structure] +invoice_number = { type = "text", description = "Invoice number" } +total = { type = "number", description = "Total amount" } + +[pipe.compose_invoice] +type = "PipeCompose" +description = "Compose an invoice from order and customer data" +inputs = { order = "Order", customer = "Customer" } +output = "Invoice" + +[pipe.compose_invoice.construct] +invoice_number = { template = "INV-$order.id" } +total = { from = "order.total_amount" } + +[pipe.compose_invoice.construct.billing_address] +street = { from = "customer.address.street" } +city = { from = "customer.address.city" } +country = "France" +``` + +##### Key Parameters (Construct Mode) + +- `construct`: Dictionary mapping field names to their composition rules +- Each field can be: + - A literal value (string, number, boolean) + - A dict with `from` key for variable reference + - A dict with `template` key for template rendering + - A nested dict for nested structures + +**Note:** You must use either `template` or `construct`, not both. They are mutually exclusive. + ### PipeImgGen operator The PipeImgGen operator is used to generate images using AI image generation models. @@ -952,13 +1087,13 @@ So here are a few concrete examples of calls to execute_pipeline with various wa }, ) -## Here we have a single input and it's a PDF. -## Because PDFContent is a native concept, we can use it directly as a value, +## Here we have a single input and it's a document. +## Because DocumentContent is a native concept, we can use it directly as a value, ## the system knows what content it corresponds to: pipe_output = await execute_pipeline( pipe_code="power_extractor_dpe", inputs={ - "document": PDFContent(url=pdf_url), + "document": DocumentContent(url=pdf_url), }, ) @@ -1081,82 +1216,4 @@ result_list = pipe_output.main_stuff_as_items(item_type=GanttChart) ``` --- - -## Rules to choose LLM models used in PipeLLMs. - -### LLM Configuration System - -In order to use it in a pipe, an LLM is referenced by its llm_handle (alias) and possibly by an llm_preset. -LLM configurations are managed through the new inference backend system with files located in `.pipelex/inference/`: - -- **Model Deck**: `.pipelex/inference/deck/base_deck.toml` and `.pipelex/inference/deck/overrides.toml` -- **Backends**: `.pipelex/inference/backends.toml` and `.pipelex/inference/backends/*.toml` -- **Routing**: `.pipelex/inference/routing_profiles.toml` - -### LLM Handles - -An llm_handle can be either: -1. **A direct model name** (like "gpt-4o-mini", "claude-3-sonnet") - automatically available for all models loaded by the inference backend system -2. **An alias** - user-defined shortcuts that map to model names, defined in the `[aliases]` section: - -```toml -[aliases] -base-claude = "claude-4.5-sonnet" -base-gpt = "gpt-5" -base-gemini = "gemini-2.5-flash" -base-mistral = "mistral-medium" -``` - -The system first looks for direct model names, then checks aliases if no direct match is found. The system handles model routing through backends automatically. - -### Using an LLM Handle in a PipeLLM - -Here is an example of using an llm_handle to specify which LLM to use in a PipeLLM: - -```plx -[pipe.hello_world] -type = "PipeLLM" -description = "Write text about Hello World." -output = "Text" -model = { model = "gpt-5", temperature = 0.9 } -prompt = """ -Write a haiku about Hello World. -""" -``` - -As you can see, to use the LLM, you must also indicate the temperature (float between 0 and 1) and max_tokens (either an int or the string "auto"). - -### LLM Presets - -Presets are meant to record the choice of an llm with its hyper parameters (temperature and max_tokens) if it's good for a particular task. LLM Presets are skill-oriented. - -Examples: -```toml -llm_to_engineer = { model = "base-claude", temperature = 1 } -llm_to_extract_invoice = { model = "claude-4.5-sonnet", temperature = 0.1, max_tokens = "auto" } -``` - -The interest is that these presets can be used to set the LLM choice in a PipeLLM, like this: - -```plx -[pipe.extract_invoice] -type = "PipeLLM" -description = "Extract invoice information from an invoice text transcript" -inputs = { invoice_text = "InvoiceText" } -output = "Invoice" -model = "llm_to_extract_invoice" -prompt = """ -Extract invoice information from this invoice: - -The category of this invoice is: $invoice_details.category. - -@invoice_text -""" -``` - -The setting here `model = "llm_to_extract_invoice"` works because "llm_to_extract_invoice" has been declared as an llm_preset in the deck. -You must not use an LLM preset in a PipeLLM that does not exist in the deck. If needed, you can add llm presets. - - -You can override the predefined llm presets by setting them in `.pipelex/inference/deck/overrides.toml`. diff --git a/Makefile b/Makefile index 803118d..bb1c61f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ VIRTUAL_ENV := $(CURDIR)/.venv PROJECT_NAME := $(shell grep '^name = ' pyproject.toml | sed -E 's/name = "(.*)"/\1/') # The "?" is used to make the variable optional, so that it can be overridden by the user. -PYTHON_VERSION ?= 3.11 +PYTHON_VERSION ?= 3.13 VENV_PYTHON := $(VIRTUAL_ENV)/bin/python VENV_PYTEST := $(VIRTUAL_ENV)/bin/pytest VENV_RUFF := $(VIRTUAL_ENV)/bin/ruff @@ -16,7 +16,7 @@ VENV_PIPELEX := $(VIRTUAL_ENV)/bin/pipelex UV_MIN_VERSION = $(shell grep -m1 'required-version' pyproject.toml | sed -E 's/.*= *"([^<>=, ]+).*/\1/') -USUAL_PYTEST_MARKERS := "(dry_runnable or not (inference or llm or imgg or ocr)) and not (needs_output or pipelex_api)" +USUAL_PYTEST_MARKERS := "(dry_runnable or not inference) and not (needs_output or pipelex_api)" define PRINT_TITLE $(eval PROJECT_PART := [$(PROJECT_NAME)]) @@ -117,7 +117,7 @@ env: check-uv $(call PRINT_TITLE,"Creating virtual environment") @if [ ! -d $(VIRTUAL_ENV) ]; then \ echo "Creating Python virtual env in \`${VIRTUAL_ENV}\`"; \ - uv venv $(VIRTUAL_ENV) --python 3.11; \ + uv venv $(VIRTUAL_ENV) --python $(PYTHON_VERSION); \ else \ echo "Python virtual env already exists in \`${VIRTUAL_ENV}\`"; \ fi @@ -209,12 +209,12 @@ cleanall: cleanderived cleanenv cleanconfig codex-tests: env $(call PRINT_TITLE,"Unit testing for Codex") @echo "• Running unit tests for Codex (excluding inference and codex_disabled)" - $(VENV_PYTEST) --exitfirst --quiet -m "not inference and not codex_disabled" || [ $$? = 5 ] + $(VENV_PYTEST) --disable-inference --exitfirst --quiet -m "not inference and not codex_disabled" || [ $$? = 5 ] gha-tests: env $(call PRINT_TITLE,"Unit testing for github actions") @echo "• Running unit tests for github actions (excluding inference and gha_disabled)" - $(VENV_PYTEST) --exitfirst --quiet -m "not inference and not gha_disabled" || [ $$? = 5 ] + $(VENV_PYTEST) --disable-inference --exitfirst --quiet -m "not inference and not gha_disabled" || [ $$? = 5 ] run-all-tests: env $(call PRINT_TITLE,"Running all unit tests") diff --git a/my_project/hello_world.py b/my_project/hello_world.py index 5614816..f70cd9e 100644 --- a/my_project/hello_world.py +++ b/my_project/hello_world.py @@ -17,8 +17,11 @@ async def hello_world(): # Print the output pretty_print(pipe_output, title="Your first Pipelex output") + # get the generated text + generated_text = pipe_output.main_stuff_as_str + pretty_print(generated_text, title="Generated text") + # start Pipelex -Pipelex.make() -# run sample using asyncio -asyncio.run(hello_world()) +with Pipelex.make(library_dirs=["my_project"]): + asyncio.run(hello_world()) diff --git a/pyproject.toml b/pyproject.toml index 1cfd5d7..fbb9661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,19 +5,22 @@ description = "Replace this with your project description" # authors = [{ name = "Your Name", email = "your.email@example.com" }] license = "MIT" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.10,<3.15" classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", ] -dependencies = [ - "pipelex[mistralai,anthropic,google,google-genai,bedrock,fal]==0.17.3", -] +dependencies = ["pipelex[mistralai,anthropic,google,google-genai,bedrock,fal]"] + +[tool.uv.sources] +pipelex = { git = "https://github.com/Pipelex/pipelex.git", branch = "pre-release/v0.18.0b3" } + [tool.setuptools] packages = ["my_project"] diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 028da5f..ab98a37 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -2,6 +2,8 @@ import pipelex.pipelex import pytest from pipelex.system.configuration.config_check import check_is_initialized +from pipelex.test_extras.shared_pytest_plugins import is_inference_disabled_in_pipelex +from pytest import FixtureRequest from rich import print from rich.console import Console from rich.traceback import Traceback @@ -15,11 +17,13 @@ def check_pipelex_initialized(): @pytest.fixture(scope="module", autouse=True) -def reset_pipelex_config_fixture(): +def reset_pipelex_config_fixture(request: FixtureRequest): # Code to run before each test print("\n[magenta]pipelex setup[/magenta]") try: - pipelex_instance = pipelex.pipelex.Pipelex.make() + pipelex_instance = pipelex.pipelex.Pipelex.make( + disable_inference=is_inference_disabled_in_pipelex(request), + ) except Exception as exc: Console().print(Traceback()) pytest.exit(f"Critical Pipelex setup error: {exc}") diff --git a/uv.lock b/uv.lock index f5923b6..44c8eb5 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.10" +requires-python = ">=3.10, <3.15" resolution-markers = [ "python_full_version >= '3.11'", "python_full_version < '3.11'", @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.75.0" +version = "0.79.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -225,9 +225,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/1f/08e95f4b7e2d35205ae5dcbb4ae97e7d477fc521c275c02609e2931ece2d/anthropic-0.75.0.tar.gz", hash = "sha256:e8607422f4ab616db2ea5baacc215dd5f028da99ce2f022e33c7c535b29f3dfb", size = 439565, upload-time = "2025-11-24T20:41:45.28Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/b1/91aea3f8fd180d01d133d931a167a78a3737b3fd39ccef2ae8d6619c24fd/anthropic-0.79.0.tar.gz", hash = "sha256:8707aafb3b1176ed6c13e2b1c9fb3efddce90d17aee5d8b83a86c70dcdcca871", size = 509825, upload-time = "2026-02-07T18:06:18.388Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/1c/1cd02b7ae64302a6e06724bf80a96401d5313708651d277b1458504a1730/anthropic-0.75.0-py3-none-any.whl", hash = "sha256:ea8317271b6c15d80225a9f3c670152746e88805a7a61e14d4a374577164965b", size = 388164, upload-time = "2025-11-24T20:41:43.587Z" }, + { url = "https://files.pythonhosted.org/packages/95/b2/cc0b8e874a18d7da50b0fda8c99e4ac123f23bf47b471827c5f6f3e4a767/anthropic-0.79.0-py3-none-any.whl", hash = "sha256:04cbd473b6bbda4ca2e41dd670fe2f829a911530f01697d0a1e37321eb75f3cf", size = 405918, upload-time = "2026-02-07T18:06:20.246Z" }, ] [[package]] @@ -343,13 +343,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/b6/f624f5143bc5f7a66b79fc40e67b30b9584471a6143062af420bc83ae887/botocore_stubs-1.41.6-py3-none-any.whl", hash = "sha256:859e4147b5b14dc5eb64fc84fa02424839354368a0fea41da52c7a1d06427e37", size = 66748, upload-time = "2025-12-01T04:14:12.833Z" }, ] +[[package]] +name = "cached-property" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/4b/3d870836119dbe9a5e3c9a61af8cc1a8b69d75aea564572e385882d5aefb/cached_property-2.0.1.tar.gz", hash = "sha256:484d617105e3ee0e4f1f58725e72a8ef9e93deee462222dbd51cd91230897641", size = 10574, upload-time = "2024-10-25T15:43:55.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/0e/7d8225aab3bc1a0f5811f8e1b557aa034ac04bdf641925b30d3caf586b28/cached_property-2.0.1-py3-none-any.whl", hash = "sha256:f617d70ab1100b7bcf6e42228f9ddcb78c676ffa167278d9f730d1c2fba69ccb", size = 7428, upload-time = "2024-10-25T15:43:54.711Z" }, +] + [[package]] name = "cachetools" -version = "6.2.2" +version = "6.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/44/ca1675be2a83aeee1886ab745b28cda92093066590233cc501890eb8417a/cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6", size = 31571, upload-time = "2025-11-13T17:42:51.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731, upload-time = "2025-12-15T18:24:53.744Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/46/eb6eca305c77a4489affe1c5d8f4cae82f285d9addd8de4ec084a7184221/cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace", size = 11503, upload-time = "2025-11-13T17:42:50.232Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551, upload-time = "2025-12-15T18:24:52.332Z" }, ] [[package]] @@ -518,11 +527,11 @@ wheels = [ [[package]] name = "eval-type-backport" -version = "0.3.0" +version = "0.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/23/079e39571d6dd8d90d7a369ecb55ad766efb6bae4e77389629e14458c280/eval_type_backport-0.3.0.tar.gz", hash = "sha256:1638210401e184ff17f877e9a2fa076b60b5838790f4532a21761cc2be67aea1", size = 9272, upload-time = "2025-11-13T20:56:50.845Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/a3/cafafb4558fd638aadfe4121dc6cefb8d743368c085acb2f521df0f3d9d7/eval_type_backport-0.3.1.tar.gz", hash = "sha256:57e993f7b5b69d271e37482e62f74e76a0276c82490cf8e4f0dffeb6b332d5ed", size = 9445, upload-time = "2025-12-02T11:51:42.987Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/d8/2a1c638d9e0aa7e269269a1a1bf423ddd94267f1a01bbe3ad03432b67dd4/eval_type_backport-0.3.0-py3-none-any.whl", hash = "sha256:975a10a0fe333c8b6260d7fdb637698c9a16c3a9e3b6eb943fee6a6f67a37fe8", size = 6061, upload-time = "2025-11-13T20:56:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl", hash = "sha256:279ab641905e9f11129f56a8a78f493518515b83402b860f6f06dd7c011fdfa8", size = 6063, upload-time = "2025-12-02T11:51:41.665Z" }, ] [[package]] @@ -530,7 +539,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -551,15 +560,17 @@ wheels = [ [[package]] name = "fal-client" -version = "0.9.1" +version = "0.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "httpx-sse" }, + { name = "msgpack" }, + { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/a1/98ab1cea4c2424ee612292bc92b07905e1a15a05584f6c263cde38e6a3a2/fal_client-0.9.1.tar.gz", hash = "sha256:c8f7f88f79c4b4c4f069be9f571be924dc7c4a6bf07c252fe0b75f3c46c8d66d", size = 17085, upload-time = "2025-11-13T18:15:09.911Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/58/223a48a4d0538e73c292086f284480be42ada14223d8067432bf5eeb7aaf/fal_client-0.11.0.tar.gz", hash = "sha256:350f8cd73f5035ae1e2678ce46beb7f9f43d0a96d43586b02cd88fd973e656e1", size = 21823, upload-time = "2026-01-05T15:22:33.606Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/57/775821a71459f2b83bbaa59452a4b1e4772f7c770de88a6f591c9d43c7c8/fal_client-0.9.1-py3-none-any.whl", hash = "sha256:8eba86c947299852c8306f685eee883ce01856543bf4344b87f65abd4b7d7622", size = 11157, upload-time = "2025-11-13T18:15:08.528Z" }, + { url = "https://files.pythonhosted.org/packages/64/67/7dd4c4b2b375cc3f072ec7bde528d7c8bafb3bcdd7df1e0758d97366a1c8/fal_client-0.11.0-py3-none-any.whl", hash = "sha256:dc4f528299aa9aeefad949e0bed0183fb78c19f0a1b7e7f85d95c859f2f694d7", size = 14771, upload-time = "2026-01-05T15:22:32.116Z" }, ] [[package]] @@ -715,6 +726,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/a4/7319a2a8add4cc352be9e3efeff5e2aacee917c85ca2fa1647e29089983c/google_auth-2.41.1-py2.py3-none-any.whl", hash = "sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d", size = 221302, upload-time = "2025-09-30T22:51:24.212Z" }, ] +[package.optional-dependencies] +requests = [ + { name = "requests" }, +] + [[package]] name = "google-auth-oauthlib" version = "1.2.3" @@ -730,21 +746,35 @@ wheels = [ [[package]] name = "google-genai" -version = "1.52.0" +version = "1.55.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "google-auth" }, + { name = "distro" }, + { name = "google-auth", extra = ["requests"] }, { name = "httpx" }, { name = "pydantic" }, { name = "requests" }, + { name = "sniffio" }, { name = "tenacity" }, { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/4e/0ad8585d05312074bb69711b2d81cfed69ce0ae441913d57bf169bed20a7/google_genai-1.52.0.tar.gz", hash = "sha256:a74e8a4b3025f23aa98d6a0f84783119012ca6c336fd68f73c5d2b11465d7fc5", size = 258743, upload-time = "2025-11-21T02:18:55.742Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7c/19b59750592702305ae211905985ec8ab56f34270af4a159fba5f0214846/google_genai-1.55.0.tar.gz", hash = "sha256:ae9f1318fedb05c7c1b671a4148724751201e8908a87568364a309804064d986", size = 477615, upload-time = "2025-12-11T02:49:28.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/86/a5a8e32b2d40b30b5fb20e7b8113fafd1e38befa4d1801abd5ce6991065a/google_genai-1.55.0-py3-none-any.whl", hash = "sha256:98c422762b5ff6e16b8d9a1e4938e8e0ad910392a5422e47f5301498d7f373a1", size = 703389, upload-time = "2025-12-11T02:49:27.105Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.72.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/66/03f663e7bca7abe9ccfebe6cb3fe7da9a118fd723a5abb278d6117e7990e/google_genai-1.52.0-py3-none-any.whl", hash = "sha256:c8352b9f065ae14b9322b949c7debab8562982f03bf71d44130cd2b798c20743", size = 261219, upload-time = "2025-11-21T02:18:54.515Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, ] [[package]] @@ -811,6 +841,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "importlib-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, +] + [[package]] name = "iniconfig" version = "2.3.0" @@ -851,6 +893,15 @@ google-genai = [ { name = "jsonref" }, ] +[[package]] +name = "invoke" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/bd/b461d3424a24c80490313fd77feeb666ca4f6a28c7e72713e3d9095719b4/invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707", size = 304762, upload-time = "2025-10-11T00:36:35.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8", size = 160287, upload-time = "2025-10-11T00:36:33.703Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -975,15 +1026,6 @@ version = "1.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/d5/40b617ee19d2d79f606ed37f8a81e51158f126d2af67270c68f2b47ae0d5/json2html-1.3.0.tar.gz", hash = "sha256:8951a53662ae9cfd812685facdba693fc950ffc1c1fd1a8a2d3cf4c34600689c", size = 6977, upload-time = "2019-07-03T20:50:03.023Z" } -[[package]] -name = "jsonpath-python" -version = "1.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/bf/626a72f2d093c5eb4f4de55b443714afa7231beeae40d4a1c69b5c5aa4d1/jsonpath_python-1.1.4.tar.gz", hash = "sha256:bb3e13854e4807c078a1503ae2d87c211b8bff4d9b40b6455ed583b3b50a7fdd", size = 84766, upload-time = "2025-11-25T12:08:39.521Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/bc/52e5bf0d9839e082b976c19afcab7561d0d719c7627483bf5dc251d27eed/jsonpath_python-1.1.4-py3-none-any.whl", hash = "sha256:8700cb8610c44da6e5e9bff50232779c44bf7dc5bc62662d49319ee746898442", size = 12687, upload-time = "2025-11-25T12:08:38.453Z" }, -] - [[package]] name = "jsonref" version = "1.1.0" @@ -1195,19 +1237,85 @@ wheels = [ [[package]] name = "mistralai" -version = "1.5.2" +version = "1.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "eval-type-backport" }, { name = "httpx" }, - { name = "jsonpath-python" }, + { name = "invoke" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-sdk" }, + { name = "opentelemetry-semantic-conventions" }, { name = "pydantic" }, { name = "python-dateutil" }, - { name = "typing-inspect" }, + { name = "pyyaml" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/8d/88b7c48878864f37c554a131d37352a4ed0ea3918df3e8cb625407ff374a/mistralai-1.5.2.tar.gz", hash = "sha256:f39e6e51e8939aac2602e4badcb18712cbee2df33d86100c559333e609b92d17", size = 133473, upload-time = "2025-03-19T18:40:29.617Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/97/5b428225ca4524b9722c8e1b2812c35f958ec5bb6a58c274c6c07a136da8/mistralai-1.5.2-py3-none-any.whl", hash = "sha256:5b1112acebbcad1afd7732ce0bd60614975b64999801c555c54768ac41f506ae", size = 278149, upload-time = "2025-03-19T18:40:28.232Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a5/6f/6e1755c7ce73c5841ee45702770e62164299ef54818db01be1b91ca263fa/mistralai-1.12.1.tar.gz", hash = "sha256:8d8637100f7ae06c31cccb9407b1f0cd7c96005a881e7221077959577c3b4d4d", size = 242499, upload-time = "2026-02-11T09:18:42.734Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/f0/81a2303a8c4cc75003c96dfacc5bd4731b2f8c1490cad6cddec1825f6d57/mistralai-1.12.1-py3-none-any.whl", hash = "sha256:045adccc3526016c951bacf8b1ee73355083b9d6a36370fce0149039ab386d56", size = 500601, upload-time = "2026-02-11T09:18:41.387Z" }, +] + +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/a2/3b68a9e769db68668b25c6108444a35f9bd163bb848c0650d516761a59c0/msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", size = 81318, upload-time = "2025-10-08T09:14:38.722Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e1/2b720cc341325c00be44e1ed59e7cfeae2678329fbf5aa68f5bda57fe728/msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", size = 83786, upload-time = "2025-10-08T09:14:40.082Z" }, + { url = "https://files.pythonhosted.org/packages/71/e5/c2241de64bfceac456b140737812a2ab310b10538a7b34a1d393b748e095/msgpack-1.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", size = 398240, upload-time = "2025-10-08T09:14:41.151Z" }, + { url = "https://files.pythonhosted.org/packages/b7/09/2a06956383c0fdebaef5aa9246e2356776f12ea6f2a44bd1368abf0e46c4/msgpack-1.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", size = 406070, upload-time = "2025-10-08T09:14:42.821Z" }, + { url = "https://files.pythonhosted.org/packages/0e/74/2957703f0e1ef20637d6aead4fbb314330c26f39aa046b348c7edcf6ca6b/msgpack-1.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", size = 393403, upload-time = "2025-10-08T09:14:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/a5/09/3bfc12aa90f77b37322fc33e7a8a7c29ba7c8edeadfa27664451801b9860/msgpack-1.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", size = 398947, upload-time = "2025-10-08T09:14:45.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4f/05fcebd3b4977cb3d840f7ef6b77c51f8582086de5e642f3fefee35c86fc/msgpack-1.1.2-cp310-cp310-win32.whl", hash = "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", size = 64769, upload-time = "2025-10-08T09:14:47.334Z" }, + { url = "https://files.pythonhosted.org/packages/d0/3e/b4547e3a34210956382eed1c85935fff7e0f9b98be3106b3745d7dec9c5e/msgpack-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", size = 71293, upload-time = "2025-10-08T09:14:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, + { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, + { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, + { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" }, + { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" }, + { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" }, + { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" }, + { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" }, + { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, + { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, + { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, + { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, + { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, + { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, + { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, + { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, + { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, + { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, + { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, + { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, + { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, + { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, + { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, + { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, + { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, ] [[package]] @@ -1377,7 +1485,7 @@ dev = [ requires-dist = [ { name = "boto3-stubs", marker = "extra == 'dev'", specifier = ">=1.35.24" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.11.2" }, - { name = "pipelex", extras = ["mistralai", "anthropic", "google", "google-genai", "bedrock", "fal"], specifier = "==0.17.3" }, + { name = "pipelex", extras = ["mistralai", "anthropic", "google", "google-genai", "bedrock", "fal"], git = "https://github.com/Pipelex/pipelex.git?branch=pre-release%2Fv0.18.0b3" }, { name = "pyright", marker = "extra == 'dev'", specifier = ">=1.1.405" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.1" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24.0" }, @@ -1657,6 +1765,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/4f/dbc0c124c40cb390508a82770fb9f6e3ed162560181a85089191a851c59a/openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463", size = 1022688, upload-time = "2025-11-17T22:39:57.675Z" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/d8/0f354c375628e048bd0570645b310797299754730079853095bf000fba69/opentelemetry_api-1.38.0.tar.gz", hash = "sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12", size = 65242, upload-time = "2025-10-16T08:35:50.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/a2/d86e01c28300bd41bab8f18afd613676e2bd63515417b77636fc1add426f/opentelemetry_api-1.38.0-py3-none-any.whl", hash = "sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582", size = 65947, upload-time = "2025-10-16T08:35:30.23Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/83/dd4660f2956ff88ed071e9e0e36e830df14b8c5dc06722dbde1841accbe8/opentelemetry_exporter_otlp_proto_common-1.38.0.tar.gz", hash = "sha256:e333278afab4695aa8114eeb7bf4e44e65c6607d54968271a249c180b2cb605c", size = 20431, upload-time = "2025-10-16T08:35:53.285Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/9e/55a41c9601191e8cd8eb626b54ee6827b9c9d4a46d736f32abc80d8039fc/opentelemetry_exporter_otlp_proto_common-1.38.0-py3-none-any.whl", hash = "sha256:03cb76ab213300fe4f4c62b7d8f17d97fcfd21b89f0b5ce38ea156327ddda74a", size = 18359, upload-time = "2025-10-16T08:35:34.099Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/0a/debcdfb029fbd1ccd1563f7c287b89a6f7bef3b2902ade56797bfd020854/opentelemetry_exporter_otlp_proto_http-1.38.0.tar.gz", hash = "sha256:f16bd44baf15cbe07633c5112ffc68229d0edbeac7b37610be0b2def4e21e90b", size = 17282, upload-time = "2025-10-16T08:35:54.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/77/154004c99fb9f291f74aa0822a2f5bbf565a72d8126b3a1b63ed8e5f83c7/opentelemetry_exporter_otlp_proto_http-1.38.0-py3-none-any.whl", hash = "sha256:84b937305edfc563f08ec69b9cb2298be8188371217e867c1854d77198d0825b", size = 19579, upload-time = "2025-10-16T08:35:36.269Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/14/f0c4f0f6371b9cb7f9fa9ee8918bfd59ac7040c7791f1e6da32a1839780d/opentelemetry_proto-1.38.0.tar.gz", hash = "sha256:88b161e89d9d372ce723da289b7da74c3a8354a8e5359992be813942969ed468", size = 46152, upload-time = "2025-10-16T08:36:01.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/6a/82b68b14efca5150b2632f3692d627afa76b77378c4999f2648979409528/opentelemetry_proto-1.38.0-py3-none-any.whl", hash = "sha256:b6ebe54d3217c42e45462e2a1ae28c3e2bf2ec5a5645236a490f55f45f1a0a18", size = 72535, upload-time = "2025-10-16T08:35:45.749Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/cb/f0eee1445161faf4c9af3ba7b848cc22a50a3d3e2515051ad8628c35ff80/opentelemetry_sdk-1.38.0.tar.gz", hash = "sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe", size = 171942, upload-time = "2025-10-16T08:36:02.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/2e/e93777a95d7d9c40d270a371392b6d6f1ff170c2a3cb32d6176741b5b723/opentelemetry_sdk-1.38.0-py3-none-any.whl", hash = "sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b", size = 132349, upload-time = "2025-10-16T08:35:46.995Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.59b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/bc/8b9ad3802cd8ac6583a4eb7de7e5d7db004e89cb7efe7008f9c8a537ee75/opentelemetry_semantic_conventions-0.59b0.tar.gz", hash = "sha256:7a6db3f30d70202d5bf9fa4b69bc866ca6a30437287de6c510fb594878aed6b0", size = 129861, upload-time = "2025-10-16T08:36:03.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/7d/c88d7b15ba8fe5c6b8f93be50fc11795e9fc05386c44afaf6b76fe191f9b/opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed", size = 207954, upload-time = "2025-10-16T08:35:48.054Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -1775,8 +1965,8 @@ wheels = [ [[package]] name = "pipelex" -version = "0.17.3" -source = { registry = "https://pypi.org/simple" } +version = "0.18.0b3" +source = { git = "https://github.com/Pipelex/pipelex.git?branch=pre-release%2Fv0.18.0b3#b6095405505fba33b9b99294e3025d769f3af7c1" } dependencies = [ { name = "aiofiles" }, { name = "backports-strenum", marker = "python_full_version < '3.11'" }, @@ -1790,8 +1980,13 @@ dependencies = [ { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "networkx", version = "3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "openai" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-sdk" }, + { name = "opentelemetry-semantic-conventions" }, { name = "pillow" }, { name = "polyfactory" }, + { name = "portkey-ai" }, { name = "posthog" }, { name = "pydantic" }, { name = "pypdfium2" }, @@ -1803,11 +1998,6 @@ dependencies = [ { name = "tomlkit" }, { name = "typer" }, { name = "typing-extensions" }, - { name = "yattag" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/69/98c518fc203b3096bf163124d3eeae8b15f8608c28e4292b977bef99bbc1/pipelex-0.17.3.tar.gz", hash = "sha256:9be425de4faee01d1039f8e97c55a2beb66e91b005be13323709f5843b917d64", size = 368295, upload-time = "2025-12-01T13:45:52.849Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/82/1ad4436608bd1c33077d9d0905a0d93640b9c47b310f1c19ae0f96c18224/pipelex-0.17.3-py3-none-any.whl", hash = "sha256:5dda80b9adcfd13433992e2dfd96f484c6339e14511388cb66adf5e22c28cafa", size = 567412, upload-time = "2025-12-01T13:45:51.07Z" }, ] [package.optional-dependencies] @@ -1863,6 +2053,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/7c/535646d75a1c510065169ea65693613c7a6bc64491bea13e7dad4f028ff3/polyfactory-3.1.0-py3-none-any.whl", hash = "sha256:78171232342c25906d542513c9f00ebf41eadec2c67b498490a577024dd7e867", size = 61836, upload-time = "2025-11-25T08:10:14.893Z" }, ] +[[package]] +name = "portkey-ai" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "cached-property" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "types-requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/8a/f5bbaab806ad61d9959cb7c88c639200feacac1b2ba7b455b97a2f216e7c/portkey_ai-2.1.0.tar.gz", hash = "sha256:c2558041c568eef8528737978089301cb9be056f166a683251831cbfa6a623cb", size = 567417, upload-time = "2025-11-25T20:32:43.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/11/c585b90ac842027e5f4f7f7cee72d3197f58ff24b6d7c5f1243aa8fa96be/portkey_ai-2.1.0-py3-none-any.whl", hash = "sha256:2166033f8e198745947fee5321d0bbcfb005afc35468bd5a948fa83dc16b6767", size = 1181622, upload-time = "2025-11-25T20:32:41.185Z" }, +] + [[package]] name = "posthog" version = "7.0.1" @@ -2010,6 +2221,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "protobuf" +version = "6.33.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296, upload-time = "2025-12-06T00:17:53.311Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603, upload-time = "2025-12-06T00:17:41.114Z" }, + { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930, upload-time = "2025-12-06T00:17:43.278Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621, upload-time = "2025-12-06T00:17:44.445Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460, upload-time = "2025-12-06T00:17:45.678Z" }, + { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168, upload-time = "2025-12-06T00:17:46.813Z" }, + { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270, upload-time = "2025-12-06T00:17:48.253Z" }, + { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501, upload-time = "2025-12-06T00:17:52.211Z" }, +] + [[package]] name = "pyasn1" version = "0.6.1" @@ -2175,22 +2401,22 @@ wheels = [ [[package]] name = "pypdfium2" -version = "5.1.0" +version = "4.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/87/56782107fa242137b77ccddc30519bbb33e7a9eed9da9649d9db45db2c64/pypdfium2-5.1.0.tar.gz", hash = "sha256:46335ca30a1584b804a6824da84d2e846b4b954bdfc342d035b7bf15ed9a14e5", size = 270104, upload-time = "2025-11-23T13:36:52.589Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239, upload-time = "2024-05-09T18:33:17.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/d7/46ce255322cd29f0db3772667a0da3db8ed137e1e9b9aa306ac5691765b3/pypdfium2-5.1.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f3dde94d320d582d3c20255b600f1e7e03261bfdea139b7064b54126fc3db4e2", size = 2817789, upload-time = "2025-11-23T13:36:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/19/a5/4ad3c1b336fdc2b7a88d835c56bcd64ce60d4a95d1a9eaafc44f853da582/pypdfium2-5.1.0-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:dee09b7a3ab1860a17decc97c179a5aaba5a74b2780d53c91daa18d742945892", size = 2940861, upload-time = "2025-11-23T13:36:33.519Z" }, - { url = "https://files.pythonhosted.org/packages/19/93/d13ca66d5e075d7e27736c51c15955cdd3266ac0a8327613c3c520d43693/pypdfium2-5.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1757d6470cbf5b8d1c825350df2ccd79fd0bfcf5753ff566fd02153a486014b1", size = 2980933, upload-time = "2025-11-23T13:36:35.283Z" }, - { url = "https://files.pythonhosted.org/packages/a2/7c/02744ef9e0363af08f9ed47c0e603ef8713e02d4a48492c76d5bf36f65c3/pypdfium2-5.1.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad18e95497423f88b33f2976cb78c27f0bd6ef4b4bf340c901f5f28a234c4f06", size = 2762960, upload-time = "2025-11-23T13:36:37.033Z" }, - { url = "https://files.pythonhosted.org/packages/89/26/f0abcfccb99b0a5c4451b70b0e72ccb7c27387931af01eae982870272202/pypdfium2-5.1.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2faee2f4fbd5bd33dd77c07d15ccaa6687562d883a54c4beb8329ebaee615b7d", size = 3060522, upload-time = "2025-11-23T13:36:38.835Z" }, - { url = "https://files.pythonhosted.org/packages/2f/74/92f508e71178aa85de32454762f84d6f9cef35c468caab3e0f1041dae464/pypdfium2-5.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d688372df169a9dad606c1e5ad34b6e0e6b820f1e0d540b4780711600a7bf8dd", size = 2995178, upload-time = "2025-11-23T13:36:40.319Z" }, - { url = "https://files.pythonhosted.org/packages/94/9f/91ca099ea64b24e19ef05da72e33d0ef0840e104d89cbdcb618da12629b5/pypdfium2-5.1.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:cfecd2b20f1c05027aaa2af6bfbcc2835b4c8f6455155b0dc2800ec6a2051965", size = 6321704, upload-time = "2025-11-23T13:36:42.177Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4b/5628cfda9f534b3acc1e2cf50f9e9582cd9cfd86cf2ce718da229de6e709/pypdfium2-5.1.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:5698de8e6d662f1b2cdff5cb62e6f0ee79ffaaa13e282251854cbc64cf712449", size = 6329892, upload-time = "2025-11-23T13:36:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/c5/25/5d2db765f8f82129d75ea2883ed26af3d1a64d8daaa20a11005ac681e2c3/pypdfium2-5.1.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:2cbd73093fbb1710ea1164cdf27583363e1b663b8cc22d555c84af0ee1af50c7", size = 6409889, upload-time = "2025-11-23T13:36:45.387Z" }, - { url = "https://files.pythonhosted.org/packages/89/d3/135ed8ca46044cd5005cd104ead13bea417777afa65d7af5a710eb68d340/pypdfium2-5.1.0-py3-none-win32.whl", hash = "sha256:11d319cd2e5f71cdc3d68e8a79142b559a0edbcc16fe31d4036fcfc45f0e9ed8", size = 2991546, upload-time = "2025-11-23T13:36:47.373Z" }, - { url = "https://files.pythonhosted.org/packages/52/8f/884a1b2fd7c747a98e9b4c95097c08b39d042a88837ac72f2945a7f6162c/pypdfium2-5.1.0-py3-none-win_amd64.whl", hash = "sha256:4725f347a8c9ff011a7035d8267ee25912ab1b946034ba0b57f3cca89de8847a", size = 3100176, upload-time = "2025-11-23T13:36:49.234Z" }, - { url = "https://files.pythonhosted.org/packages/d7/5c/72448636ea0ccd44878f77bb5d59a2c967a54eec806ee2e0d894ef0d2434/pypdfium2-5.1.0-py3-none-win_arm64.whl", hash = "sha256:47c5593f7eb6ae0f1e5a940d712d733ede580f09ca91de6c3f89611848695c0f", size = 2941500, upload-time = "2025-11-23T13:36:50.69Z" }, + { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254, upload-time = "2024-05-09T18:32:48.653Z" }, + { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624, upload-time = "2024-05-09T18:32:51.458Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126, upload-time = "2024-05-09T18:32:53.581Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077, upload-time = "2024-05-09T18:32:55.99Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431, upload-time = "2024-05-09T18:32:57.911Z" }, + { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008, upload-time = "2024-05-09T18:32:59.886Z" }, + { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543, upload-time = "2024-05-09T18:33:02.597Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911, upload-time = "2024-05-09T18:33:05.376Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430, upload-time = "2024-05-09T18:33:08.067Z" }, + { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951, upload-time = "2024-05-09T18:33:10.567Z" }, + { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098, upload-time = "2024-05-09T18:33:13.107Z" }, + { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118, upload-time = "2024-05-09T18:33:15.489Z" }, ] [[package]] @@ -2705,6 +2931,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, ] +[[package]] +name = "types-requests" +version = "2.32.4.20250913" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/27/489922f4505975b11de2b5ad07b4fe1dca0bca9be81a703f26c5f3acfce5/types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d", size = 23113, upload-time = "2025-09-13T02:40:02.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/20/9a227ea57c1285986c4cf78400d0a91615d25b24e257fd9e2969606bdfae/types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1", size = 20658, upload-time = "2025-09-13T02:40:01.115Z" }, +] + [[package]] name = "types-s3transfer" version = "0.15.0" @@ -2723,19 +2961,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, -] - [[package]] name = "typing-inspection" version = "0.4.2" @@ -3036,7 +3261,10 @@ wheels = [ ] [[package]] -name = "yattag" -version = "1.16.1" +name = "zipp" +version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/1a/d3b2a2b8f843f5e7138471c4a5c9172ef62bb41239aa4371784b7448110c/yattag-1.16.1.tar.gz", hash = "sha256:baa8f254e7ea5d3e0618281ad2ff5610e0e5360b3608e695c29bfb3b29d051f4", size = 29069, upload-time = "2024-11-02T22:38:30.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +]