mistralai-workflows-cli 1.2.1__tar.gz → 1.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/.gitignore +3 -0
  2. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/Makefile +6 -0
  3. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/PKG-INFO +1 -1
  4. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/pyproject.toml +1 -2
  5. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/SKILL.md +15 -3
  6. mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/connectors.mdx +178 -0
  7. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/limitations.mdx +11 -0
  8. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/rate-limiting.mdx +3 -2
  9. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/workflows-plugins.mdx +66 -0
  10. mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/scripts/linting/rules/determinism.yaml +217 -0
  11. mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/scripts/linting/rules/imports.yaml +114 -0
  12. mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/scripts/linting/rules/io.yaml +116 -0
  13. mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/scripts/linting/rules/structure.yaml +120 -0
  14. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/scripts/test_workflow.py +88 -73
  15. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/Makefile +22 -1
  16. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/pyproject.toml.jinja +1 -0
  17. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/entrypoints/start.py +1 -3
  18. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/entrypoints/worker.py +3 -5
  19. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/activities.py +5 -15
  20. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/models.py +3 -9
  21. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/workflow.py +4 -11
  22. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/activities.py +7 -23
  23. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/models.py +4 -12
  24. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/workflow.py +2 -6
  25. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/activities.py +1 -3
  26. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/models.py +0 -1
  27. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/workflow.py +1 -4
  28. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/linear_summarization/__init__.py +1 -1
  29. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/linear_summarization/linear_activities.py +5 -20
  30. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/linear_summarization/summary_activity.py +2 -8
  31. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/linear_summarization/workflow.py +2 -7
  32. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/worker.py +2 -3
  33. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/workflows/hello.py +1 -2
  34. {mistralai_workflows_cli-1.2.1/src/mistral_workflows_cli/_template/template/src → mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template}/worker.py +1 -1
  35. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/README.md +0 -0
  36. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/__init__.py +0 -0
  37. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/copier.yml +0 -0
  38. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/execution_ids.md +0 -0
  39. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/core-concepts.mdx +0 -0
  40. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/installation.mdx +0 -0
  41. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/introduction.mdx +0 -0
  42. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/python-sdk.mdx +0 -0
  43. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/value-proposition.mdx +0 -0
  44. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/getting-started/your-first-workflow.mdx +0 -0
  45. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/_deployment-patterns.mdx +0 -0
  46. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/activities.mdx +0 -0
  47. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/assist-workflows.mdx +0 -0
  48. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/concurrency.mdx +0 -0
  49. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/dependency-injection.mdx +0 -0
  50. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/diagnostics.md +0 -0
  51. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/durable-agents.mdx +0 -0
  52. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/error-codes.mdx +0 -0
  53. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/handling-large-data.mdx +0 -0
  54. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/local-execution.mdx +0 -0
  55. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/migration-v2-to-v3.mdx +0 -0
  56. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/observability.mdx +0 -0
  57. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/payload-encoding.mdx +0 -0
  58. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/scheduling.mdx +0 -0
  59. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/signals-queries-updates.mdx +0 -0
  60. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/streaming-consumption.mdx +0 -0
  61. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/streaming.mdx +0 -0
  62. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/testing.md +0 -0
  63. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/workflows-exception.mdx +0 -0
  64. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/guides/workflows.mdx +0 -0
  65. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/pipeline_pattern.md +0 -0
  66. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.agents/skills/workflows/references/workflow_testing.md +0 -0
  67. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.env.jinja +0 -0
  68. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/.gitignore +0 -0
  69. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/README.md.jinja +0 -0
  70. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/entrypoints/__init__.py +0 -0
  71. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/entrypoints/dev.py +0 -0
  72. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/__init__.py +0 -0
  73. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/README.md +0 -0
  74. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/__init__.py +0 -0
  75. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/sample_data/shipping_doc_anomaly.png +0 -0
  76. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/cargo_release/sample_data/shipping_doc_normal.png +0 -0
  77. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/README.md +0 -0
  78. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/__init__.py +0 -0
  79. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sample_data/legacy_repo/__init__.py +0 -0
  80. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sample_data/legacy_repo/api_client.py +0 -0
  81. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sample_data/legacy_repo/processor.py +0 -0
  82. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sample_data/legacy_repo/utils.py +0 -0
  83. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sub_workflow.py +0 -0
  84. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/README.md +0 -0
  85. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/__init__.py +0 -0
  86. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/claim_high_severity.json +0 -0
  87. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/claim_low_severity.json +0 -0
  88. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/claim_medium_severity.json +0 -0
  89. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/photos/CREDITS.md +0 -0
  90. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/photos/claim_high_totaled_front.jpg +0 -0
  91. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/photos/claim_high_totaled_side.jpg +0 -0
  92. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/photos/claim_low_scratch_door.jpg +0 -0
  93. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/insurance_claims/sample_data/photos/claim_medium_dent_rear.jpg +0 -0
  94. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/examples/linear_summarization/README.md +0 -0
  95. {mistralai_workflows_cli-1.2.1/src/mistral_workflows_cli/_template/template → mistralai_workflows_cli-1.2.3/src/mistral_workflows_cli/_template/template/src}/worker.py +0 -0
  96. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_template/template/src/workflows/__init__.py +0 -0
  97. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/_version.py +0 -0
  98. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/main.py +0 -0
  99. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/src/mistral_workflows_cli/setup.py +0 -0
  100. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/tests/__init__.py +0 -0
  101. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/tests/test_setup.py +0 -0
  102. {mistralai_workflows_cli-1.2.1 → mistralai_workflows_cli-1.2.3}/uv.lock +0 -0
@@ -219,6 +219,9 @@ jobs/run/checkpoints/test/consolidated/params.json
219
219
 
220
220
  # Cursor plans folder
221
221
  .cursor/plans/
222
+
223
+ # Agent plans (scratch planning docs)
224
+ .agents/plans/
222
225
  tsconfig.tsbuildinfo
223
226
 
224
227
  .vscode-test/
@@ -42,6 +42,7 @@ integration-test:
42
42
  $(MAKE) _test-start-examples
43
43
  $(MAKE) _test-execute-help
44
44
  $(MAKE) _test-execute-bad-json
45
+ $(MAKE) _test-make-check
45
46
  $(MAKE) _test-wheel-contents
46
47
  @echo ""
47
48
  @echo "All integration tests passed."
@@ -124,3 +125,8 @@ _test-wheel-contents:
124
125
  | grep -q "entrypoints/worker.py" \
125
126
  && echo "OK: wheel contains entrypoints package" \
126
127
  || (echo "FAIL: wheel is missing the entrypoints package" && exit 1)
128
+
129
+ _test-make-check:
130
+ @echo "--- test: 'make check' (ruff, mypy, workflow lint) passes on the generated project"
131
+ cd $(GENERATED_PROJECT) && $(MAKE) check
132
+ @echo "OK: make check passes on the generated project"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mistralai-workflows-cli
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: CLI to bootstrap Mistral Workflows projects
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: click>=8.0
@@ -32,8 +32,7 @@ packages = ["src/mistral_workflows_cli"]
32
32
 
33
33
  [tool.ruff]
34
34
  line-length = 120
35
- # The copier template is project data, not part of the CLI's own source.
36
- extend-exclude = ["src/mistral_workflows_cli/_template"]
35
+ extend-exclude = ["src/mistral_workflows_cli/_template/template/src/examples/code_modernization/sample_data/legacy_repo"]
37
36
 
38
37
  [tool.ruff.lint]
39
38
  select = ["E", "F", "I", "UP"]
@@ -73,10 +73,11 @@ The documentation is organized into several categories:
73
73
  - **[Payload Encoding](references/guides/payload-encoding.mdx)**: Payload offloading, AES-GCM encryption, key rotation
74
74
  - **[Observability](references/guides/observability.mdx)**: OpenTelemetry traces, trace sampling
75
75
  - **[Durable Agents](references/guides/durable-agents.mdx)**: Agent, Runner, RemoteSession/LocalSession, MCP, multi-agent handoffs
76
+ - **[Connectors](references/guides/connectors.mdx)**: Call third-party tools (GitHub, Notion, Slack, ...) from a workflow or give them to an agent, without holding the service's credentials
76
77
  - **[Conversational Workflows](references/guides/assist-workflows.mdx)**: InteractiveWorkflow, HITL, ChatInput/FormInput, Canvas editing, Rich UI components, Tool UI states
77
78
  - **[Local Execution](references/guides/local-execution.mdx)**: No-infra dev mode with Pydantic model params
78
- - **[Limitations](references/guides/limitations.mdx)**: System constraints and limits
79
- - **[Workflows Plugins](references/guides/workflows-plugins.mdx)**: Mistral AI plugin, Webhook plugin, Nuage plugin, custom plugins
79
+ - **[Limitations](references/guides/limitations.mdx)**: System constraints, determinism rules, sandbox import restrictions (module-level non-deterministic imports + `imports_passed_through`), I/O and heavy work belongs in activities, execution-history limits
80
+ - **[Workflows Plugins](references/guides/workflows-plugins.mdx)**: Mistral AI plugin (calling chat / structured-output / embeddings / OCR models), Webhook plugin, Nuage plugin, custom plugins
80
81
  - **[Deployment Patterns](references/guides/_deployment-patterns.mdx)**: Best practices for deploying workflows
81
82
  - **[Migration v2 to v3](references/guides/migration-v2-to-v3.mdx)**: Breaking changes and upgrade steps from SDK v2 through v3.4.0
82
83
 
@@ -100,6 +101,16 @@ python .agents/skills/workflows/scripts/test_workflow.py <workflow_file> --input
100
101
 
101
102
  If a workflow is known to be long-running (e.g. multi-step agent, large data processing), increase timeouts proportionally — but start short and only raise them when you see legitimate timeout failures, not preemptively.
102
103
 
104
+ **Lint & check** — validate your code before running it. Three checks are available:
105
+ - `make lint` — Ruff: style, imports, and common errors (`make format` auto-fixes most)
106
+ - `make typecheck` — mypy static type checking
107
+ - `make lint-workflows` — Semgrep workflow rules: determinism violations, I/O outside activities, missing return-type annotations, unsafe imports (advisory — reports but does not block)
108
+
109
+ Run all three at once after writing or editing a workflow, and address any findings:
110
+ ```bash
111
+ make check
112
+ ```
113
+
103
114
  ### Internal References
104
115
 
105
116
  These are additional patterns and utilities not covered in the official docs:
@@ -121,6 +132,7 @@ Use this skill when you need to:
121
132
  7. **Build conversational workflows**: Create interactive workflows with HITL, forms, canvas, and rich UI
122
133
  8. **Ensure fault tolerance**: Implement systems that can recover from failures automatically
123
134
  9. **Stream events**: Real-time token streaming and progress updates via NATS
135
+ 10. **Integrate external services**: Call GitHub, Notion, Slack, and other connectors with platform-managed credentials
124
136
 
125
137
  ## Key Features
126
138
 
@@ -135,5 +147,5 @@ Use this skill when you need to:
135
147
  - **Large payload handling**: OffloadableField with S3/Azure/GCS blob storage
136
148
  - **Conversational workflows**: Interactive workflows with Vibe integration, forms, canvas, and rich UI components
137
149
  - **Durable agents**: AI agents with MCP support, multi-agent handoffs, and persistent state
150
+ - **Connectors**: Call external services with platform-managed credentials avoiding secrets in the workflow code
138
151
  - **Scalability**: Designed to handle complex, distributed applications
139
-
@@ -0,0 +1,178 @@
1
+ ---
2
+ id: connectors
3
+ title: Connectors
4
+ sidebar_position: 8
5
+ ---
6
+
7
+ # Connectors in Workflows
8
+
9
+ Connectors let workflows call external services (GitHub, Notion, Slack, ...) using credentials managed by the Mistral Connectors platform. The workflow **declares** which connectors it needs; the platform resolves credentials and drives any OAuth flow automatically. The same code works whether the connector uses a bearer/PAT token or OAuth2. **You never put secrets in workflow code**.
10
+
11
+ Connectors ship in the Mistral plugin:
12
+
13
+ ```bash
14
+ uv add 'mistralai-workflows[mistralai]'
15
+ ```
16
+
17
+ ### Discovering configured connectors
18
+
19
+ The `name` you pass to `connector(...)` must match a connector already configured for the workspace, don't guess them ever! To see the configured connectors and their exact names, run:
20
+
21
+ ```bash
22
+ uv run python -c "from dotenv import load_dotenv; load_dotenv(); import os; from mistralai.client import Mistral; print(*[c.name for c in Mistral(api_key=os.environ['MISTRAL_API_KEY']).beta.connectors.list().items], sep='\n')"
23
+ ```
24
+
25
+ For a connector's tools, use `list_tools` (returns a plain list, not `.items`) and don't guess them even if you think you know how they must be called!:
26
+
27
+ ```bash
28
+ uv run python -c "from dotenv import load_dotenv; load_dotenv(); import os; from mistralai.client import Mistral; print(*[t.name for t in Mistral(api_key=os.environ['MISTRAL_API_KEY']).beta.connectors.list_tools(connector_id_or_name='github_app')], sep='\n')"
29
+ ```
30
+
31
+ Each tool also has `.jsonschema` for its `arguments` (add `t.jsonschema` to the print when you need it).
32
+ (You only need these calls to figure out how to write the code. Don't put these snippets in the workflow itself.)
33
+
34
+ ## Declaring connectors in a workflow
35
+
36
+ Three pieces wire a connector in:
37
+
38
+ 1. `connector("name")` — declares a **connector slot**.
39
+ 2. `@uses_connectors(...)` — attaches slots to the workflow class; apply it **after** `@workflow.define` (on the line below).
40
+ 3. `Depends(slot)` — injects a `ToolCallClient` into an activity.
41
+
42
+ ```python
43
+ import pydantic
44
+ import mistralai.workflows as workflows
45
+ from mistralai.workflows import Depends
46
+ from mistralai.workflows.plugins.mistralai.connectors import (
47
+ ToolCallClient,
48
+ connector,
49
+ uses_connectors,
50
+ )
51
+
52
+ github = connector("github_app")
53
+
54
+
55
+ class CreateIssueInput(pydantic.BaseModel):
56
+ owner: str
57
+ repo: str
58
+ title: str
59
+ body: str
60
+
61
+
62
+ @workflows.activity(name="create-github-issue")
63
+ async def create_github_issue(
64
+ owner: str,
65
+ repo: str,
66
+ title: str,
67
+ body: str,
68
+ client: ToolCallClient = Depends(github),
69
+ ) -> None:
70
+ await client.call_tool(
71
+ tool_name="issue_write",
72
+ arguments={
73
+ "method": "create",
74
+ "owner": owner,
75
+ "repo": repo,
76
+ "title": title,
77
+ "body": body,
78
+ },
79
+ )
80
+
81
+
82
+ @workflows.workflow.define(name="github-issue-creator")
83
+ @uses_connectors(github)
84
+ class GitHubIssueCreatorWorkflow:
85
+ @workflows.workflow.entrypoint
86
+ async def run(self, prompt: CreateIssueInput) -> None:
87
+ await create_github_issue(prompt.owner, prompt.repo, prompt.title, prompt.body)
88
+ ```
89
+
90
+ Watch out for:
91
+
92
+ - **Import path** is `mistralai.workflows.plugins.mistralai.connectors` (repeated `mistralai`), not `...plugins.connectors`.
93
+ - **`@uses_connectors` is required** and sits **below** `@workflow.define`. Without it, credentials are never resolved and `call_tool` fails.
94
+ - A `ToolCallClient` only works **inside an activity** (it resolves credentials from the workflow context at call time). A failed call raises `ConnectorToolCallError` (non-retryable).
95
+ - **Tool names and argument schemas are connector-specific** (e.g. GitHub's `issue_write`, Notion's `notion-create-pages`) and aren't inferable from the SDK types. Discover them with `client.beta.connectors.list_tools_async(connector_id_or_name=...)` or take them from the task — don't guess.
96
+ - **No special worker setup** — the Mistral plugin auto-registers the connector auth interceptor; run on a normal worker.
97
+
98
+ ### `connector(...)` parameters
99
+
100
+ | Parameter | Default | Purpose |
101
+ | --- | --- | --- |
102
+ | `name` (positional) | — | Must match a connector configured for the workspace; discover via `client.beta.connectors.list_async()`. |
103
+ | `auto_auth` | `True` | Run the OAuth preflight before the workflow starts. |
104
+ | `credentials_name` | `None` | Pin a specific named credential set; otherwise the user's default is used. |
105
+ | `allow_mcp_ui` | `False` | Surface an MCP tool's `_meta.ui.resourceUri` as a side app in Vibe after a matching tool call (fire-and-forget — the workflow doesn't wait for or consume the result). |
106
+
107
+ ## Acting as the user (on-behalf-of)
108
+
109
+ A connector call runs as one of two identities:
110
+
111
+ - **The triggering user** — set `on_behalf_of=True` on `@workflow.define`, and the connector uses the credentials *that user* authorized (their GitHub, their Notion, ...).
112
+ - **The worker** (default) — the connector uses the worker's own stored credentials: one shared service identity for every run.
113
+
114
+ ```python
115
+ @workflows.workflow.define(name="github-issue-creator", on_behalf_of=True)
116
+ @uses_connectors(github)
117
+ class GitHubIssueCreatorWorkflow:
118
+ ...
119
+ ```
120
+
121
+ Fall back to worker credentials (omit `on_behalf_of`) when there's no triggering user or you deliberately want one shared identity. Caveats (platform-enforced):
122
+
123
+ - **Needs a triggering user.** Starting an `on_behalf_of=True` workflow without a user session is rejected (`403 "On-behalf-of workflows require user identity"`). For the same reason it **can't be combined with `schedules`** — the SDK raises at definition time, since a scheduled run has no triggering user.
124
+ - **Restricted to Mistral-internal orgs.** Registering an `on_behalf_of=True` workflow returns `403 "on_behalf workflows are currently restricted to Mistral-internal organizations"` unless the org is internal or the `ON_BEHALF_WORKFLOWS_ENABLED` feature flag is enabled.
125
+
126
+ ## Connectors in durable agents
127
+
128
+ Pass slots to an `Agent` via `connectors=[...]` so it can call connector tools autonomously. Keep `@uses_connectors` on the workflow. See the [Durable Agents](durable-agents.mdx) guide for agent/runner output handling.
129
+
130
+ ```python
131
+ import mistralai.workflows as workflows
132
+ from mistralai.workflows.plugins.mistralai import Agent, Runner
133
+ from mistralai.workflows.plugins.mistralai.connectors import connector, uses_connectors
134
+
135
+ github = connector("github_app")
136
+
137
+
138
+ @workflows.workflow.define(name="github-agent")
139
+ @uses_connectors(github)
140
+ class GitHubAgentWorkflow:
141
+ @workflows.workflow.entrypoint
142
+ async def run(self, repo: str) -> str:
143
+ agent = Agent(
144
+ name="github-pr-lister",
145
+ model="mistral-medium-latest",
146
+ instructions=f"List recent pull requests on {repo}.",
147
+ connectors=[github], # connector tools available to the agent
148
+ )
149
+ outputs = await Runner.run(agent=agent, inputs=f"Summarize PRs on {repo}.")
150
+ return await extract_text(outputs)
151
+ ```
152
+
153
+ OAuth and credential resolution still happen automatically.
154
+
155
+ ## Running a connector workflow
156
+
157
+ You usually don't run these by hand, they're triggered from Studio/the UI (which shows the OAuth prompt) or by whatever starts the workflow. To trigger one **from Python** when it may need OAuth, use `execute_with_connector_auth_async` (`mistralai.extra.workflows`): it surfaces the auth URL via an `on_auth_required(state)` callback and resumes automatically once the user authorizes. For plain execution without OAuth, see the [Python SDK](../getting-started/python-sdk.mdx) guide.
158
+
159
+ ## Common errors
160
+
161
+ | Symptom | Cause / fix |
162
+ | --- | --- |
163
+ | `RuntimeError: No workflow context available` | `ToolCallClient` used outside an activity. Inject via `Depends` and call tools inside an `@activity`. |
164
+ | Credentials never resolve / `call_tool` fails | Missing `@uses_connectors`, or the connector `name` doesn't match a configured connector (check `client.beta.connectors.list_async()`). |
165
+ | `ConnectorAuthTimeout` | OAuth not completed within 10 minutes. Re-run and authorize promptly. |
166
+ | `ConnectorToolCallError` | The connector tool rejected the call — check `tool_name` and the `arguments` schema. |
167
+ | `ImportError` for connectors | Install the extra: `uv add 'mistralai-workflows[mistralai]'`; import from `mistralai.workflows.plugins.mistralai.connectors`. |
168
+
169
+ ## Quick reference
170
+
171
+ | Symbol | Import from | Use |
172
+ | --- | --- | --- |
173
+ | `connector(name, *, auto_auth, credentials_name, allow_mcp_ui)` | `mistralai.workflows.plugins.mistralai.connectors` | Declare a connector slot. |
174
+ | `uses_connectors(*slots)` | same | Class decorator; attach slots (after `@workflow.define`). |
175
+ | `ToolCallClient` / `.call_tool(tool_name, arguments)` | same | Call connector tools from an activity (inject via `Depends`). |
176
+ | `Agent(..., connectors=[...])` | `mistralai.workflows.plugins.mistralai` | Give a durable agent connector tools. |
177
+ | `execute_with_connector_auth_async(...)` | `mistralai.extra.workflows` | Run a connector workflow from Python, handling OAuth (trigger-side, not needed to build a workflow). |
178
+ | `client.beta.connectors.list_async()` / `list_tools_async(connector_id_or_name=)` | `mistralai` client | Discover configured connectors and their tool names/schemas. |
@@ -144,6 +144,17 @@ if os.getenv("ENV") == "prod":
144
144
 
145
145
  must be performed in activities. While activities themselves can produce different outputs for the same inputs (as they might contain non-deterministic operations), the workflow code must behave deterministically based on the activity results it receives.
146
146
 
147
+ ### Imports must be deterministic too
148
+
149
+ The sandbox also validates **imports**. A module-level `import` of a non-deterministic library (`httpx`, `requests`, `aiohttp`, the raw `mistralai` client, etc.) in a workflow file won't work in the sandbox — the worker rejects it while validating the workflow at startup, so the workflow never becomes runnable. Keep such imports **inside the activity** that uses them, or — when a top-level import is unavoidable (e.g. shared type hints) — wrap it so the sandbox lets it through:
150
+
151
+ ```python
152
+ with workflows.workflow.unsafe.imports_passed_through():
153
+ import httpx
154
+ ```
155
+
156
+ Only pass through imports you know are side-effect-free (no import-time I/O or global-state mutation).
157
+
147
158
  ### Maximum Execution History
148
159
 
149
160
  The execution history for each workflow is capped at 51,200 events or 50MB per workflow execution. This is a hard limit of the durable execution engine. In order to avoid hitting this limit, we recommend using `workflows.execute_activities_in_parallel`, that allows you to execute large amounts of activities in parallel, while having the lowest footprint on the execution history. [Learn more about concurrency patterns](concurrency).
@@ -28,7 +28,8 @@ When **a key is provided**, multiple different activities that use the same key
28
28
 
29
29
  ```python
30
30
  import mistralai.workflows as workflows
31
- from mistralai import Mistral, Messages
31
+ from mistralai.client import Mistral
32
+ from mistralai.client.models import ChatCompletionRequestMessage
32
33
  from mistralai.workflows import Depends
33
34
  from pydantic import BaseModel
34
35
 
@@ -41,7 +42,7 @@ def get_mistral_client() -> Mistral:
41
42
 
42
43
  class CompletionParams(BaseModel):
43
44
  model: str
44
- messages: Messages
45
+ messages: list[ChatCompletionRequestMessage]
45
46
 
46
47
  @workflows.activity(rate_limit=workflows.RateLimit(time_window_in_sec=1, max_calls=100))
47
48
  async def generate_chat_response(
@@ -78,6 +78,72 @@ class SummarizeWorkflow:
78
78
  return result.choices[0].message.content
79
79
  ```
80
80
 
81
+ **Example — structured output:** to get a validated Pydantic object back instead of a string, define a model and build the same `ChatCompletionRequest` as above, then swap the final call for `chat_parse_to_model`:
82
+
83
+ ```python
84
+ from pydantic import BaseModel
85
+ from mistralai.workflows.plugins.mistralai import chat_parse_to_model
86
+
87
+ class Sentiment(BaseModel):
88
+ label: str
89
+ score: float
90
+
91
+ # inside the entrypoint, with `request` built as in the chat example above:
92
+ sentiment = await chat_parse_to_model(Sentiment, request)
93
+ ```
94
+
95
+ For the raw response instead of a parsed model, call `mistralai_chat_parse(request, response_format)` directly.
96
+
97
+ **Example — embeddings** (call from inside an entrypoint or activity):
98
+
99
+ ```python
100
+ from mistralai.workflows.plugins.mistralai import (
101
+ MistralEmbeddingsParams,
102
+ mistralai_embeddings,
103
+ )
104
+
105
+ response = await mistralai_embeddings(
106
+ MistralEmbeddingsParams(model="mistral-embed", inputs=["first text", "second text"]),
107
+ )
108
+ vectors = [item.embedding for item in response.data]
109
+ ```
110
+
111
+ **Example — OCR** extracts text from a document or image URL:
112
+
113
+ ```python
114
+ from mistralai.client.models import DocumentURLChunk
115
+ from mistralai.workflows.plugins.mistralai import OCRRequest, mistralai_ocr
116
+
117
+ result = await mistralai_ocr(
118
+ OCRRequest(
119
+ model="mistral-ocr-latest",
120
+ document=DocumentURLChunk(document_url="https://example.com/invoice.pdf"),
121
+ ),
122
+ )
123
+ pages_markdown = [page.markdown for page in result.pages]
124
+ ```
125
+
126
+ **Raw client (when a plugin activity isn't enough):** call the Mistral API directly from inside an activity. Import the client from `mistralai.client` — `mistralai` is a namespace package, so `from mistralai import Mistral` does **not** work — and keep that import inside the activity function so the workflow sandbox doesn't reject it:
127
+
128
+ ```python
129
+ import os
130
+ from mistralai.workflows import activity
131
+
132
+ @activity()
133
+ async def summarize(text: str) -> str:
134
+ # Import inside the activity so the workflow sandbox doesn't reject it.
135
+ from mistralai.client import Mistral # NOT `from mistralai import Mistral`
136
+
137
+ client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
138
+ resp = await client.chat.complete_async(
139
+ model="mistral-small-latest",
140
+ messages=[{"role": "user", "content": text}],
141
+ )
142
+ return resp.choices[0].message.content
143
+ ```
144
+
145
+ Model calls and other I/O must run inside an activity, never in the workflow body; see [Limitations](./limitations) for the determinism and import rules.
146
+
81
147
  For full documentation on `Agent`, `Runner`, sessions, MCP, and multi-agent handoffs, see the [Durable Agents guide](./durable-agents).
82
148
 
83
149
  ### Webhook Plugin
@@ -0,0 +1,217 @@
1
+ rules:
2
+ # Workflow code runs inside a determinism sandbox and is replayed on
3
+ # recovery. Non-deterministic operations break replay. These rules
4
+ # flag non-deterministic stdlib calls inside `@workflow.define` classes
5
+ # (the workflow classes). Activities and plain helper classes are exempt.
6
+
7
+ - id: no-datetime-now-in-workflow
8
+ patterns:
9
+ - pattern-either:
10
+ - pattern: datetime.now(...)
11
+ - pattern: datetime.datetime.now(...)
12
+ - pattern: datetime.utcnow(...)
13
+ - pattern: datetime.datetime.utcnow(...)
14
+ - pattern-either:
15
+ - pattern-inside: |
16
+ @workflow.define(...)
17
+ class $CLASS:
18
+ ...
19
+ - pattern-inside: |
20
+ @workflows.workflow.define(...)
21
+ class $CLASS:
22
+ ...
23
+ message: >-
24
+ Use `workflow.now()` instead of `datetime.now()` in workflow code.
25
+ Workflows must be deterministic — `datetime.now()` returns
26
+ different values on replay, breaking the execution history.
27
+ severity: ERROR
28
+ languages: [python]
29
+ metadata:
30
+ category: determinism
31
+ fix: Replace with `workflow.now()` from `mistralai.workflows`
32
+
33
+ - id: no-uuid4-in-workflow
34
+ patterns:
35
+ - pattern-either:
36
+ - pattern: uuid.uuid4(...)
37
+ - pattern: uuid4(...)
38
+ - pattern-either:
39
+ - pattern-inside: |
40
+ @workflow.define(...)
41
+ class $CLASS:
42
+ ...
43
+ - pattern-inside: |
44
+ @workflows.workflow.define(...)
45
+ class $CLASS:
46
+ ...
47
+ message: >-
48
+ Use `workflow.uuid4()` instead of `uuid.uuid4()` in workflow code.
49
+ Standard UUID generation is non-deterministic and breaks replay.
50
+ severity: ERROR
51
+ languages: [python]
52
+ metadata:
53
+ category: determinism
54
+ fix: Replace with `workflow.uuid4()` from `mistralai.workflows`
55
+
56
+ - id: no-random-in-workflow
57
+ patterns:
58
+ - pattern-either:
59
+ - pattern: random.random(...)
60
+ - pattern: random.randint(...)
61
+ - pattern: random.choice(...)
62
+ - pattern: random.shuffle(...)
63
+ - pattern: random.sample(...)
64
+ - pattern: random.uniform(...)
65
+ - pattern: random.randrange(...)
66
+ - pattern: random.gauss(...)
67
+ - pattern-either:
68
+ - pattern-inside: |
69
+ @workflow.define(...)
70
+ class $CLASS:
71
+ ...
72
+ - pattern-inside: |
73
+ @workflows.workflow.define(...)
74
+ class $CLASS:
75
+ ...
76
+ message: >-
77
+ Use `workflow.random()` instead of the `random` module in workflow
78
+ code. Standard random functions are non-deterministic and break
79
+ replay.
80
+ severity: ERROR
81
+ languages: [python]
82
+ metadata:
83
+ category: determinism
84
+ fix: Replace with `workflow.random()` from `mistralai.workflows`
85
+
86
+ - id: no-os-env-in-workflow
87
+ patterns:
88
+ - pattern-either:
89
+ - pattern: os.environ
90
+ - pattern: os.environ[...]
91
+ - pattern: os.environ.get(...)
92
+ - pattern: os.getenv(...)
93
+ - pattern: os.getcwd(...)
94
+ - pattern: os.listdir(...)
95
+ - pattern: os.path.exists(...)
96
+ - pattern-either:
97
+ - pattern-inside: |
98
+ @workflow.define(...)
99
+ class $CLASS:
100
+ ...
101
+ - pattern-inside: |
102
+ @workflows.workflow.define(...)
103
+ class $CLASS:
104
+ ...
105
+ message: >-
106
+ Do not access `os.environ`, `os.getenv()`, `os.getcwd()`, or
107
+ filesystem functions in workflow code. Environment variables and
108
+ filesystem state can differ between replays. Read config in an
109
+ activity and pass it as workflow input, or use dependency injection.
110
+ severity: ERROR
111
+ languages: [python]
112
+ metadata:
113
+ category: determinism
114
+ fix: Move to an activity or use dependency injection (Depends)
115
+
116
+ - id: no-time-in-workflow
117
+ patterns:
118
+ - pattern-either:
119
+ - pattern: time.time(...)
120
+ - pattern: time.monotonic(...)
121
+ - pattern: time.sleep(...)
122
+ - pattern-either:
123
+ - pattern-inside: |
124
+ @workflow.define(...)
125
+ class $CLASS:
126
+ ...
127
+ - pattern-inside: |
128
+ @workflows.workflow.define(...)
129
+ class $CLASS:
130
+ ...
131
+ message: >-
132
+ Do not use `time.time()`, `time.monotonic()`, or `time.sleep()`
133
+ in workflow code. Use `workflow.now()` for timestamps and
134
+ `asyncio.sleep()` for delays (which is durable and survives
135
+ replays).
136
+ severity: ERROR
137
+ languages: [python]
138
+ metadata:
139
+ category: determinism
140
+ fix: Use `workflow.now()` for time, `asyncio.sleep()` for delays
141
+
142
+ - id: no-hashlib-in-workflow
143
+ patterns:
144
+ - pattern-either:
145
+ - pattern: hashlib.sha256(...)
146
+ - pattern: hashlib.sha512(...)
147
+ - pattern: hashlib.md5(...)
148
+ - pattern: hashlib.sha1(...)
149
+ - pattern: hashlib.new(...)
150
+ - pattern: hashlib.pbkdf2_hmac(...)
151
+ - pattern-either:
152
+ - pattern-inside: |
153
+ @workflow.define(...)
154
+ class $CLASS:
155
+ ...
156
+ - pattern-inside: |
157
+ @workflows.workflow.define(...)
158
+ class $CLASS:
159
+ ...
160
+ message: >-
161
+ Cryptographic operations are CPU-intensive and can exceed the
162
+ 2-second limit between activities. Move hashing to an activity:
163
+ @activity()
164
+ async def hash_data(data: bytes) -> str:
165
+ return hashlib.sha256(data).hexdigest()
166
+ severity: WARNING
167
+ languages: [python]
168
+ metadata:
169
+ category: determinism
170
+ fix: Move cryptographic operations to an activity
171
+
172
+ - id: no-global-in-workflow
173
+ patterns:
174
+ - pattern: global $VAR
175
+ - pattern-either:
176
+ - pattern-inside: |
177
+ @workflow.define(...)
178
+ class $CLASS:
179
+ ...
180
+ - pattern-inside: |
181
+ @workflows.workflow.define(...)
182
+ class $CLASS:
183
+ ...
184
+ message: >-
185
+ Do not use `global` in workflow code. Modifying global variables
186
+ is non-deterministic — the global state may differ between
187
+ replays. Store state on `self` or pass it through activities.
188
+ severity: ERROR
189
+ languages: [python]
190
+ metadata:
191
+ category: determinism
192
+ fix: Use `self.field` for workflow state, or pass data via activities
193
+
194
+ - id: no-model-validate-in-workflow
195
+ patterns:
196
+ - pattern: $MODEL.model_validate(...)
197
+ - pattern-either:
198
+ - pattern-inside: |
199
+ @workflow.define(...)
200
+ class $CLASS:
201
+ ...
202
+ - pattern-inside: |
203
+ @workflows.workflow.define(...)
204
+ class $CLASS:
205
+ ...
206
+ message: >-
207
+ Pydantic `.model_validate()` can be CPU-intensive on large
208
+ payloads and may exceed the 2-second limit between activities.
209
+ Move heavy validation to an activity:
210
+ @activity()
211
+ async def validate(data: dict) -> MyModel:
212
+ return MyModel.model_validate(data)
213
+ severity: WARNING
214
+ languages: [python]
215
+ metadata:
216
+ category: determinism
217
+ fix: Move validation to an activity