telize 0.2.2__tar.gz → 0.3.0__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.
- {telize-0.2.2 → telize-0.3.0}/PKG-INFO +48 -39
- {telize-0.2.2 → telize-0.3.0}/README.md +47 -38
- telize-0.3.0/examples/chat_input.yaml +26 -0
- {telize-0.2.2 → telize-0.3.0}/examples/llm_loop.yaml +0 -1
- {telize-0.2.2 → telize-0.3.0}/examples/llm_save_output.yaml +1 -1
- {telize-0.2.2 → telize-0.3.0}/examples/read_directory.yaml +1 -0
- {telize-0.2.2 → telize-0.3.0}/examples/spec_reference.yaml +5 -2
- {telize-0.2.2 → telize-0.3.0}/pyproject.toml +1 -1
- telize-0.3.0/src/telize/__version__.py +1 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/cli.py +2 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/models/__init__.py +2 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/models/actions.py +31 -11
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/models/config.py +10 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/console/__init__.py +1 -1
- {telize-0.2.2 → telize-0.3.0}/src/telize/console/display.py +3 -10
- {telize-0.2.2 → telize-0.3.0}/src/telize/console/observer.py +37 -2
- telize-0.3.0/src/telize/console/terminal.py +12 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/base.py +17 -0
- telize-0.3.0/src/telize/runtime/actions/chat.py +54 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/input.py +3 -3
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/llm.py +3 -33
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/registry.py +2 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/context.py +3 -2
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/observer.py +12 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/runner.py +83 -50
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/state.py +1 -0
- telize-0.3.0/tests/fixtures/loop_workflow.yaml +18 -0
- telize-0.3.0/tests/test_chat_action.py +119 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_cli.py +31 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_console_display.py +4 -4
- telize-0.3.0/tests/test_console_observer.py +63 -0
- telize-0.3.0/tests/test_input_action.py +61 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_models.py +7 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_observer.py +36 -0
- telize-0.3.0/tests/test_repeat.py +196 -0
- telize-0.3.0/tests/test_runner.py +40 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_version.py +8 -1
- {telize-0.2.2 → telize-0.3.0}/uv.lock +1 -1
- telize-0.2.2/src/telize/__version__.py +0 -1
- telize-0.2.2/tests/test_console_observer.py +0 -35
- telize-0.2.2/tests/test_runner.py +0 -16
- {telize-0.2.2 → telize-0.3.0}/.github/workflows/ci.yml +0 -0
- {telize-0.2.2 → telize-0.3.0}/.github/workflows/publish.yml +0 -0
- {telize-0.2.2 → telize-0.3.0}/.gitignore +0 -0
- {telize-0.2.2 → telize-0.3.0}/.python-version +0 -0
- {telize-0.2.2 → telize-0.3.0}/CHANGELOG.md +0 -0
- {telize-0.2.2 → telize-0.3.0}/CONTRIBUTING.md +0 -0
- {telize-0.2.2 → telize-0.3.0}/LICENSE +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/call_subflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/data/notes/alpha.md +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/data/notes/beta.md +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/data/sample.txt +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/env_config.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/minimal_llm.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/multi_model.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/nested_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/nested_workflow_child.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/python_step.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/read_file.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/shell_to_llm.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/shell_with_env.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/examples/show.gif +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/__main__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/loader.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/models/flow.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/config/models/spec.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/exceptions.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/providers/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/providers/base.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/providers/openai.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/providers/registry.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/py.typed +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/python.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/shell.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/actions/yaml.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/paths.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/planning.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/runtime/workflow_input.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/templating/__init__.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/templating/context.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/templating/load.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/src/telize/templating/renderer.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/conftest.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/cli_input_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/external_child_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/hello_agent_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/invalid_duplicate_step.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/minimal_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/shell_only.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/yaml_child_config_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/fixtures/yaml_input_workflow.yaml +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_llm_system_prompt.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_loader.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_loader_env.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_openai_provider.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_planning.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_templating.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_templating_load.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_workflow_input.py +0 -0
- {telize-0.2.2 → telize-0.3.0}/tests/test_yaml_action.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: telize
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Automate with flows, not loose prompts. Chain LLM, shell, and code in one YAML pipeline.
|
|
5
5
|
Project-URL: Homepage, https://github.com/telize-ai/telize
|
|
6
6
|
Project-URL: Documentation, https://github.com/telize-ai/telize#readme
|
|
@@ -36,50 +36,50 @@ Requires-Dist: ruff>=0.9; extra == 'dev'
|
|
|
36
36
|
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
37
37
|
Description-Content-Type: text/markdown
|
|
38
38
|
|
|
39
|
-
# Telize
|
|
39
|
+
# 🚀 Telize
|
|
40
40
|
|
|
41
41
|
**Build reproducible, structured AI workflows with YAML and run them from your terminal, combining LLMs, shell, Python, and more—fully under your control.**
|
|
42
42
|
|
|
43
43
|
Telize is a low-code framework for building agent-style pipelines: chain shell commands, file I/O, LLM calls, Python functions, and nested flows in a single workflow file. Configuration is validated before execution, and the CLI shows live progress as each step completes.
|
|
44
44
|
|
|
45
|
-

|
|
45
|
+

|
|
46
46
|
|
|
47
47
|
[CI](https://github.com/telize-ai/telize/actions/workflows/ci.yml) · [Python 3.12+](https://www.python.org/downloads/) · [License](LICENSE)
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
51
|
-
## Table of contents
|
|
51
|
+
## 🧭 Table of contents
|
|
52
52
|
|
|
53
|
-
- [Features](
|
|
54
|
-
- [Requirements](
|
|
55
|
-
- [Installation](
|
|
56
|
-
- [Quick start](
|
|
57
|
-
- [Motivation](#-motivation)
|
|
58
|
-
- [How it works](
|
|
59
|
-
- [Workflow reference](
|
|
60
|
-
- [Examples](
|
|
61
|
-
- [CLI](
|
|
62
|
-
- [Development](
|
|
63
|
-
- [Contributing](
|
|
64
|
-
- [License](
|
|
53
|
+
- [✨ Features](#-features)
|
|
54
|
+
- [🧩 Requirements](#-requirements)
|
|
55
|
+
- [📦 Installation](#-installation)
|
|
56
|
+
- [⚡ Quick start](#-quick-start)
|
|
57
|
+
- [🚀 Motivation](#-motivation)
|
|
58
|
+
- [⚙️ How it works](#-how-it-works)
|
|
59
|
+
- [📚 Workflow reference](#-workflow-reference)
|
|
60
|
+
- [🧪 Examples](#-examples)
|
|
61
|
+
- [💻 CLI](#-cli)
|
|
62
|
+
- [🛠️ Development](#-development)
|
|
63
|
+
- [🤝 Contributing](#-contributing)
|
|
64
|
+
- [📄 License](#-license)
|
|
65
65
|
|
|
66
|
-
## Features
|
|
66
|
+
## ✨ Features
|
|
67
67
|
|
|
68
68
|
- **YAML workflows** — one file defines `config`, named `models`, flows, and steps
|
|
69
69
|
- **Composable steps** — `input`, `llm`, `shell`, `python`, `flow`, and `yaml` actions
|
|
70
70
|
- **Jinja templating** — wire step outputs together with `{{ steps.name.output }}`
|
|
71
|
-
- **Loops and sub-flows** — iterate
|
|
71
|
+
- **Loops and sub-flows** — add `loop` to any step to iterate it over split lists; call nested flows with `uses: flow`
|
|
72
72
|
- **Validated upfront** — Pydantic models catch schema errors before any step runs
|
|
73
73
|
- **Rich CLI output** — progress, step panels, and errors in the terminal
|
|
74
74
|
- **OpenAI-compatible LLMs** — official OpenAI API or local [Ollama](https://ollama.com/) via the same client
|
|
75
75
|
|
|
76
|
-
## Requirements
|
|
76
|
+
## 🧩 Requirements
|
|
77
77
|
|
|
78
78
|
- **Python 3.12+**
|
|
79
79
|
- **LLM endpoint** for `uses: llm` steps — [OpenAI](https://platform.openai.com/) or [Ollama](https://ollama.com/); set `api_url` on each model profile (default `http://localhost:11434`)
|
|
80
80
|
- Optional: [uv](https://docs.astral.sh/uv/) for fast local development
|
|
81
81
|
|
|
82
|
-
## Installation
|
|
82
|
+
## 📦 Installation
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
85
|
pip install telize
|
|
@@ -100,7 +100,7 @@ Check the install:
|
|
|
100
100
|
telize --version
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
## Quick start
|
|
103
|
+
## ⚡ Quick start
|
|
104
104
|
|
|
105
105
|
**1.** For local models, start [Ollama](https://ollama.com/) and pull a model:
|
|
106
106
|
|
|
@@ -163,7 +163,7 @@ By treating LLMs as just another step in a standard automation pipeline, it brin
|
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
166
|
-
###
|
|
166
|
+
### 🧠 Why it works
|
|
167
167
|
- **Deterministic Structure + Non-Deterministic AI:**
|
|
168
168
|
It keeps the overall architecture _rigid and predictable_ (`YAML`), while allowing the AI to handle the _fuzzy, creative tasks_ (**text generation, summarization**) within strict boundaries.
|
|
169
169
|
- **Upfront Validation:**
|
|
@@ -185,7 +185,7 @@ By treating LLMs as just another step in a standard automation pipeline, it brin
|
|
|
185
185
|
|
|
186
186
|
---
|
|
187
187
|
|
|
188
|
-
###
|
|
188
|
+
### ⚠️ Where Telize Might Struggle (_The Limitations_)
|
|
189
189
|
While it is great for **structured automation**, it isn’t a silver bullet:
|
|
190
190
|
|
|
191
191
|
- **Dynamic Decision Making:**
|
|
@@ -195,7 +195,7 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
195
195
|
|
|
196
196
|
---
|
|
197
197
|
|
|
198
|
-
## How it works
|
|
198
|
+
## ⚙️ How it works
|
|
199
199
|
|
|
200
200
|
1. Telize loads your YAML and validates it against typed Pydantic models.
|
|
201
201
|
2. The flow named in `config.entrypoint` runs first.
|
|
@@ -203,9 +203,9 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
203
203
|
4. Later steps can reference earlier outputs via Jinja templates.
|
|
204
204
|
5. The CLI prints progress and results as the workflow runs.
|
|
205
205
|
|
|
206
|
-
## Workflow reference
|
|
206
|
+
## 📚 Workflow reference
|
|
207
207
|
|
|
208
|
-
### Top-level structure
|
|
208
|
+
### 🧱 Top-level structure
|
|
209
209
|
|
|
210
210
|
| Key | Description |
|
|
211
211
|
| -------- | ------------------------------------------------------------------- |
|
|
@@ -213,13 +213,14 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
213
213
|
| `models` | Named LLM profiles; referenced by `model:` on each `uses: llm` step |
|
|
214
214
|
| `flows` | Named flows; `config.entrypoint` must match one of these keys |
|
|
215
215
|
|
|
216
|
-
### `config`
|
|
216
|
+
### ⚙️ `config`
|
|
217
217
|
|
|
218
218
|
| Field | Description |
|
|
219
219
|
| ------------ | ------------------------------------------------- |
|
|
220
220
|
| `entrypoint` | Name of the flow to run when the file is executed |
|
|
221
|
+
| `repeat` | Optional repeat interval in seconds. Omitted, `null`, or `-1`: run once. `0`: restart immediately after each run finishes. `N > 0`: restart `N` seconds after each run started; if a run exceeds `N` seconds, restart immediately when it finishes |
|
|
221
222
|
|
|
222
|
-
### `models`
|
|
223
|
+
### 🤖 `models`
|
|
223
224
|
|
|
224
225
|
Each key under `models` is a profile name (for example `default`, `creative`). LLM steps pick a profile with `model: <name>`.
|
|
225
226
|
|
|
@@ -258,24 +259,32 @@ models:
|
|
|
258
259
|
api_url: http://{{ env.OLLAMA_HOST }}:11434
|
|
259
260
|
```
|
|
260
261
|
|
|
261
|
-
### Flow
|
|
262
|
+
### 🌊 Flow
|
|
262
263
|
|
|
263
264
|
| Field | Description |
|
|
264
265
|
| ------- | --------------------------------------------------------- |
|
|
265
266
|
| `steps` | List of steps (unique `name` per flow), executed in order |
|
|
266
267
|
|
|
267
|
-
|
|
268
|
+
Every step also supports:
|
|
269
|
+
|
|
270
|
+
| Field | Description |
|
|
271
|
+
| ------------ | --------------------------------------------------------------------------- |
|
|
272
|
+
| `name` | Unique id within the flow; referenced as `{{ steps.<name>.output }}` |
|
|
273
|
+
| `output_to` | Optional path (relative to the workflow file); raw step output is written when the step finishes |
|
|
274
|
+
| `loop` | Optional; run the step once per item (`items` split by `split_by`, default `\n<|separator|>\n`), exposing each as `{{ item }}` and joining outputs with `separator` (default `\n<|separator|>\n`) |
|
|
275
|
+
|
|
276
|
+
### 🪜 Steps (`uses`)
|
|
268
277
|
|
|
269
278
|
| `uses` | Description |
|
|
270
279
|
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
271
|
-
| `input` | Read a `file` or a `directory` (with glob `include`)
|
|
272
|
-
| `llm` | Send a `prompt` using a named `model` from `models
|
|
280
|
+
| `input` | Read a `file` or a `directory` (with glob `include`; optional `separator` when joining directory files, default `\n<|separator|>\n`) |
|
|
281
|
+
| `llm` | Send a `prompt` using a named `model` from `models` |
|
|
273
282
|
| `shell` | Run `run` commands; optional `envs` (supports templates) |
|
|
274
283
|
| `python` | Call `call` (`module.function`) with `args` |
|
|
275
284
|
| `flow` | Run another flow via `run` |
|
|
276
285
|
| `yaml` | Run an external workflow from `file` (own `config`, `models`, and `flows`); optional `input` map passed to the child as `{{ input.key }}` |
|
|
277
286
|
|
|
278
|
-
### Templating
|
|
287
|
+
### 🧩 Templating
|
|
279
288
|
|
|
280
289
|
Telize uses [Jinja2](https://jinja.palletsprojects.com/) in step fields.
|
|
281
290
|
|
|
@@ -303,7 +312,7 @@ Example — chain a shell step into an LLM step:
|
|
|
303
312
|
{{ steps.fetch_data.output }}
|
|
304
313
|
```
|
|
305
314
|
|
|
306
|
-
## Examples
|
|
315
|
+
## 🧪 Examples
|
|
307
316
|
|
|
308
317
|
| File | What it demonstrates |
|
|
309
318
|
| ---------------------------------------------------------------- | -------------------------------------------------------- |
|
|
@@ -312,7 +321,7 @@ Example — chain a shell step into an LLM step:
|
|
|
312
321
|
| [`examples/shell_to_llm.yaml`](examples/shell_to_llm.yaml) | Shell → LLM with `{{ steps.*.output }}` |
|
|
313
322
|
| [`examples/read_file.yaml`](examples/read_file.yaml) | `uses: input` — single file |
|
|
314
323
|
| [`examples/read_directory.yaml`](examples/read_directory.yaml) | `uses: input` — directory glob |
|
|
315
|
-
| [`examples/llm_save_output.yaml`](examples/llm_save_output.yaml) | `output_to` — persist
|
|
324
|
+
| [`examples/llm_save_output.yaml`](examples/llm_save_output.yaml) | `output_to` — persist step output to disk |
|
|
316
325
|
| [`examples/llm_loop.yaml`](examples/llm_loop.yaml) | `loop` — split output and iterate |
|
|
317
326
|
| [`examples/call_subflow.yaml`](examples/call_subflow.yaml) | `uses: flow` — sub-flow in the same file |
|
|
318
327
|
| [`examples/nested_workflow.yaml`](examples/nested_workflow.yaml) | `uses: yaml` — external workflow + `input` |
|
|
@@ -321,7 +330,7 @@ Example — chain a shell step into an LLM step:
|
|
|
321
330
|
| [`examples/shell_with_env.yaml`](examples/shell_with_env.yaml) | Shell `envs` and load-time `{{ env.* }}` |
|
|
322
331
|
| [`examples/env_config.yaml`](examples/env_config.yaml) | `{{ env.VAR }}` in the `models` section at load time |
|
|
323
332
|
|
|
324
|
-
## CLI
|
|
333
|
+
## 💻 CLI
|
|
325
334
|
|
|
326
335
|
```
|
|
327
336
|
usage: telize [-h] [--version] [-f FILE] [--validate-only]
|
|
@@ -333,7 +342,7 @@ options:
|
|
|
333
342
|
--validate-only parse and validate without running steps
|
|
334
343
|
```
|
|
335
344
|
|
|
336
|
-
## Development
|
|
345
|
+
## 🛠️ Development
|
|
337
346
|
|
|
338
347
|
```bash
|
|
339
348
|
uv sync
|
|
@@ -345,11 +354,11 @@ uv run mypy
|
|
|
345
354
|
|
|
346
355
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for pull request guidelines and [CHANGELOG.md](CHANGELOG.md) for release notes.
|
|
347
356
|
|
|
348
|
-
## Contributing
|
|
357
|
+
## 🤝 Contributing
|
|
349
358
|
|
|
350
359
|
Contributions are welcome — bug reports, docs, and pull requests. Please read [CONTRIBUTING.md](CONTRIBUTING.md) and open an [issue](https://github.com/telize-ai/telize/issues) before large changes.
|
|
351
360
|
|
|
352
|
-
## License
|
|
361
|
+
## 📄 License
|
|
353
362
|
|
|
354
363
|
Apache License 2.0 — see [LICENSE](LICENSE).
|
|
355
364
|
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
# Telize
|
|
1
|
+
# 🚀 Telize
|
|
2
2
|
|
|
3
3
|
**Build reproducible, structured AI workflows with YAML and run them from your terminal, combining LLMs, shell, Python, and more—fully under your control.**
|
|
4
4
|
|
|
5
5
|
Telize is a low-code framework for building agent-style pipelines: chain shell commands, file I/O, LLM calls, Python functions, and nested flows in a single workflow file. Configuration is validated before execution, and the CLI shows live progress as each step completes.
|
|
6
6
|
|
|
7
|
-

|
|
7
|
+

|
|
8
8
|
|
|
9
9
|
[CI](https://github.com/telize-ai/telize/actions/workflows/ci.yml) · [Python 3.12+](https://www.python.org/downloads/) · [License](LICENSE)
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## Table of contents
|
|
13
|
+
## 🧭 Table of contents
|
|
14
14
|
|
|
15
|
-
- [Features](
|
|
16
|
-
- [Requirements](
|
|
17
|
-
- [Installation](
|
|
18
|
-
- [Quick start](
|
|
19
|
-
- [Motivation](#-motivation)
|
|
20
|
-
- [How it works](
|
|
21
|
-
- [Workflow reference](
|
|
22
|
-
- [Examples](
|
|
23
|
-
- [CLI](
|
|
24
|
-
- [Development](
|
|
25
|
-
- [Contributing](
|
|
26
|
-
- [License](
|
|
15
|
+
- [✨ Features](#-features)
|
|
16
|
+
- [🧩 Requirements](#-requirements)
|
|
17
|
+
- [📦 Installation](#-installation)
|
|
18
|
+
- [⚡ Quick start](#-quick-start)
|
|
19
|
+
- [🚀 Motivation](#-motivation)
|
|
20
|
+
- [⚙️ How it works](#-how-it-works)
|
|
21
|
+
- [📚 Workflow reference](#-workflow-reference)
|
|
22
|
+
- [🧪 Examples](#-examples)
|
|
23
|
+
- [💻 CLI](#-cli)
|
|
24
|
+
- [🛠️ Development](#-development)
|
|
25
|
+
- [🤝 Contributing](#-contributing)
|
|
26
|
+
- [📄 License](#-license)
|
|
27
27
|
|
|
28
|
-
## Features
|
|
28
|
+
## ✨ Features
|
|
29
29
|
|
|
30
30
|
- **YAML workflows** — one file defines `config`, named `models`, flows, and steps
|
|
31
31
|
- **Composable steps** — `input`, `llm`, `shell`, `python`, `flow`, and `yaml` actions
|
|
32
32
|
- **Jinja templating** — wire step outputs together with `{{ steps.name.output }}`
|
|
33
|
-
- **Loops and sub-flows** — iterate
|
|
33
|
+
- **Loops and sub-flows** — add `loop` to any step to iterate it over split lists; call nested flows with `uses: flow`
|
|
34
34
|
- **Validated upfront** — Pydantic models catch schema errors before any step runs
|
|
35
35
|
- **Rich CLI output** — progress, step panels, and errors in the terminal
|
|
36
36
|
- **OpenAI-compatible LLMs** — official OpenAI API or local [Ollama](https://ollama.com/) via the same client
|
|
37
37
|
|
|
38
|
-
## Requirements
|
|
38
|
+
## 🧩 Requirements
|
|
39
39
|
|
|
40
40
|
- **Python 3.12+**
|
|
41
41
|
- **LLM endpoint** for `uses: llm` steps — [OpenAI](https://platform.openai.com/) or [Ollama](https://ollama.com/); set `api_url` on each model profile (default `http://localhost:11434`)
|
|
42
42
|
- Optional: [uv](https://docs.astral.sh/uv/) for fast local development
|
|
43
43
|
|
|
44
|
-
## Installation
|
|
44
|
+
## 📦 Installation
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
pip install telize
|
|
@@ -62,7 +62,7 @@ Check the install:
|
|
|
62
62
|
telize --version
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
## Quick start
|
|
65
|
+
## ⚡ Quick start
|
|
66
66
|
|
|
67
67
|
**1.** For local models, start [Ollama](https://ollama.com/) and pull a model:
|
|
68
68
|
|
|
@@ -125,7 +125,7 @@ By treating LLMs as just another step in a standard automation pipeline, it brin
|
|
|
125
125
|
|
|
126
126
|
---
|
|
127
127
|
|
|
128
|
-
###
|
|
128
|
+
### 🧠 Why it works
|
|
129
129
|
- **Deterministic Structure + Non-Deterministic AI:**
|
|
130
130
|
It keeps the overall architecture _rigid and predictable_ (`YAML`), while allowing the AI to handle the _fuzzy, creative tasks_ (**text generation, summarization**) within strict boundaries.
|
|
131
131
|
- **Upfront Validation:**
|
|
@@ -147,7 +147,7 @@ By treating LLMs as just another step in a standard automation pipeline, it brin
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
-
###
|
|
150
|
+
### ⚠️ Where Telize Might Struggle (_The Limitations_)
|
|
151
151
|
While it is great for **structured automation**, it isn’t a silver bullet:
|
|
152
152
|
|
|
153
153
|
- **Dynamic Decision Making:**
|
|
@@ -157,7 +157,7 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
157
157
|
|
|
158
158
|
---
|
|
159
159
|
|
|
160
|
-
## How it works
|
|
160
|
+
## ⚙️ How it works
|
|
161
161
|
|
|
162
162
|
1. Telize loads your YAML and validates it against typed Pydantic models.
|
|
163
163
|
2. The flow named in `config.entrypoint` runs first.
|
|
@@ -165,9 +165,9 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
165
165
|
4. Later steps can reference earlier outputs via Jinja templates.
|
|
166
166
|
5. The CLI prints progress and results as the workflow runs.
|
|
167
167
|
|
|
168
|
-
## Workflow reference
|
|
168
|
+
## 📚 Workflow reference
|
|
169
169
|
|
|
170
|
-
### Top-level structure
|
|
170
|
+
### 🧱 Top-level structure
|
|
171
171
|
|
|
172
172
|
| Key | Description |
|
|
173
173
|
| -------- | ------------------------------------------------------------------- |
|
|
@@ -175,13 +175,14 @@ While it is great for **structured automation**, it isn’t a silver bullet:
|
|
|
175
175
|
| `models` | Named LLM profiles; referenced by `model:` on each `uses: llm` step |
|
|
176
176
|
| `flows` | Named flows; `config.entrypoint` must match one of these keys |
|
|
177
177
|
|
|
178
|
-
### `config`
|
|
178
|
+
### ⚙️ `config`
|
|
179
179
|
|
|
180
180
|
| Field | Description |
|
|
181
181
|
| ------------ | ------------------------------------------------- |
|
|
182
182
|
| `entrypoint` | Name of the flow to run when the file is executed |
|
|
183
|
+
| `repeat` | Optional repeat interval in seconds. Omitted, `null`, or `-1`: run once. `0`: restart immediately after each run finishes. `N > 0`: restart `N` seconds after each run started; if a run exceeds `N` seconds, restart immediately when it finishes |
|
|
183
184
|
|
|
184
|
-
### `models`
|
|
185
|
+
### 🤖 `models`
|
|
185
186
|
|
|
186
187
|
Each key under `models` is a profile name (for example `default`, `creative`). LLM steps pick a profile with `model: <name>`.
|
|
187
188
|
|
|
@@ -220,24 +221,32 @@ models:
|
|
|
220
221
|
api_url: http://{{ env.OLLAMA_HOST }}:11434
|
|
221
222
|
```
|
|
222
223
|
|
|
223
|
-
### Flow
|
|
224
|
+
### 🌊 Flow
|
|
224
225
|
|
|
225
226
|
| Field | Description |
|
|
226
227
|
| ------- | --------------------------------------------------------- |
|
|
227
228
|
| `steps` | List of steps (unique `name` per flow), executed in order |
|
|
228
229
|
|
|
229
|
-
|
|
230
|
+
Every step also supports:
|
|
231
|
+
|
|
232
|
+
| Field | Description |
|
|
233
|
+
| ------------ | --------------------------------------------------------------------------- |
|
|
234
|
+
| `name` | Unique id within the flow; referenced as `{{ steps.<name>.output }}` |
|
|
235
|
+
| `output_to` | Optional path (relative to the workflow file); raw step output is written when the step finishes |
|
|
236
|
+
| `loop` | Optional; run the step once per item (`items` split by `split_by`, default `\n<|separator|>\n`), exposing each as `{{ item }}` and joining outputs with `separator` (default `\n<|separator|>\n`) |
|
|
237
|
+
|
|
238
|
+
### 🪜 Steps (`uses`)
|
|
230
239
|
|
|
231
240
|
| `uses` | Description |
|
|
232
241
|
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
233
|
-
| `input` | Read a `file` or a `directory` (with glob `include`)
|
|
234
|
-
| `llm` | Send a `prompt` using a named `model` from `models
|
|
242
|
+
| `input` | Read a `file` or a `directory` (with glob `include`; optional `separator` when joining directory files, default `\n<|separator|>\n`) |
|
|
243
|
+
| `llm` | Send a `prompt` using a named `model` from `models` |
|
|
235
244
|
| `shell` | Run `run` commands; optional `envs` (supports templates) |
|
|
236
245
|
| `python` | Call `call` (`module.function`) with `args` |
|
|
237
246
|
| `flow` | Run another flow via `run` |
|
|
238
247
|
| `yaml` | Run an external workflow from `file` (own `config`, `models`, and `flows`); optional `input` map passed to the child as `{{ input.key }}` |
|
|
239
248
|
|
|
240
|
-
### Templating
|
|
249
|
+
### 🧩 Templating
|
|
241
250
|
|
|
242
251
|
Telize uses [Jinja2](https://jinja.palletsprojects.com/) in step fields.
|
|
243
252
|
|
|
@@ -265,7 +274,7 @@ Example — chain a shell step into an LLM step:
|
|
|
265
274
|
{{ steps.fetch_data.output }}
|
|
266
275
|
```
|
|
267
276
|
|
|
268
|
-
## Examples
|
|
277
|
+
## 🧪 Examples
|
|
269
278
|
|
|
270
279
|
| File | What it demonstrates |
|
|
271
280
|
| ---------------------------------------------------------------- | -------------------------------------------------------- |
|
|
@@ -274,7 +283,7 @@ Example — chain a shell step into an LLM step:
|
|
|
274
283
|
| [`examples/shell_to_llm.yaml`](examples/shell_to_llm.yaml) | Shell → LLM with `{{ steps.*.output }}` |
|
|
275
284
|
| [`examples/read_file.yaml`](examples/read_file.yaml) | `uses: input` — single file |
|
|
276
285
|
| [`examples/read_directory.yaml`](examples/read_directory.yaml) | `uses: input` — directory glob |
|
|
277
|
-
| [`examples/llm_save_output.yaml`](examples/llm_save_output.yaml) | `output_to` — persist
|
|
286
|
+
| [`examples/llm_save_output.yaml`](examples/llm_save_output.yaml) | `output_to` — persist step output to disk |
|
|
278
287
|
| [`examples/llm_loop.yaml`](examples/llm_loop.yaml) | `loop` — split output and iterate |
|
|
279
288
|
| [`examples/call_subflow.yaml`](examples/call_subflow.yaml) | `uses: flow` — sub-flow in the same file |
|
|
280
289
|
| [`examples/nested_workflow.yaml`](examples/nested_workflow.yaml) | `uses: yaml` — external workflow + `input` |
|
|
@@ -283,7 +292,7 @@ Example — chain a shell step into an LLM step:
|
|
|
283
292
|
| [`examples/shell_with_env.yaml`](examples/shell_with_env.yaml) | Shell `envs` and load-time `{{ env.* }}` |
|
|
284
293
|
| [`examples/env_config.yaml`](examples/env_config.yaml) | `{{ env.VAR }}` in the `models` section at load time |
|
|
285
294
|
|
|
286
|
-
## CLI
|
|
295
|
+
## 💻 CLI
|
|
287
296
|
|
|
288
297
|
```
|
|
289
298
|
usage: telize [-h] [--version] [-f FILE] [--validate-only]
|
|
@@ -295,7 +304,7 @@ options:
|
|
|
295
304
|
--validate-only parse and validate without running steps
|
|
296
305
|
```
|
|
297
306
|
|
|
298
|
-
## Development
|
|
307
|
+
## 🛠️ Development
|
|
299
308
|
|
|
300
309
|
```bash
|
|
301
310
|
uv sync
|
|
@@ -307,11 +316,11 @@ uv run mypy
|
|
|
307
316
|
|
|
308
317
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for pull request guidelines and [CHANGELOG.md](CHANGELOG.md) for release notes.
|
|
309
318
|
|
|
310
|
-
## Contributing
|
|
319
|
+
## 🤝 Contributing
|
|
311
320
|
|
|
312
321
|
Contributions are welcome — bug reports, docs, and pull requests. Please read [CONTRIBUTING.md](CONTRIBUTING.md) and open an [issue](https://github.com/telize-ai/telize/issues) before large changes.
|
|
313
322
|
|
|
314
|
-
## License
|
|
323
|
+
## 📄 License
|
|
315
324
|
|
|
316
325
|
Apache License 2.0 — see [LICENSE](LICENSE).
|
|
317
326
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Pause the workflow and ask the user for input with uses: chat.
|
|
2
|
+
config:
|
|
3
|
+
entrypoint: main
|
|
4
|
+
|
|
5
|
+
models:
|
|
6
|
+
default:
|
|
7
|
+
provider: openai
|
|
8
|
+
model: gpt-4o-mini
|
|
9
|
+
api_url: https://api.openai.com/v1
|
|
10
|
+
|
|
11
|
+
flows:
|
|
12
|
+
main:
|
|
13
|
+
steps:
|
|
14
|
+
- name: user_chat
|
|
15
|
+
uses: chat
|
|
16
|
+
message: |
|
|
17
|
+
What would you like help with today?
|
|
18
|
+
|
|
19
|
+
- name: respond
|
|
20
|
+
uses: llm
|
|
21
|
+
model: default
|
|
22
|
+
prompt: |
|
|
23
|
+
The user said:
|
|
24
|
+
{{ steps.user_chat.output }}
|
|
25
|
+
|
|
26
|
+
Reply briefly and helpfully.
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
config:
|
|
16
16
|
# entrypoint — name of the flow that runs when you execute this file
|
|
17
17
|
entrypoint: release_pipeline
|
|
18
|
+
# repeat — optional; omit, null, or -1 to run once. 0 restarts immediately after
|
|
19
|
+
# each run finishes. N>0 restarts N seconds after each run started (or immediately
|
|
20
|
+
# if the run took longer than N seconds).
|
|
21
|
+
# repeat: 0
|
|
18
22
|
|
|
19
23
|
# models — named LLM profiles referenced by `model:` on llm steps
|
|
20
24
|
models:
|
|
@@ -63,7 +67,7 @@ flows:
|
|
|
63
67
|
|
|
64
68
|
Draft Documents:
|
|
65
69
|
{{ steps.fetch_context_docs.output }}
|
|
66
|
-
# output_to — optional path; raw
|
|
70
|
+
# output_to — optional path; raw step output is written when the step finishes
|
|
67
71
|
output_to: ./reports/documentation_gap_analysis.md
|
|
68
72
|
|
|
69
73
|
- name: generate_marketing_copy
|
|
@@ -89,7 +93,6 @@ flows:
|
|
|
89
93
|
loop:
|
|
90
94
|
items: "{{ steps.get_keywords.output }}"
|
|
91
95
|
split_by: ","
|
|
92
|
-
execution: sequential # or parallel
|
|
93
96
|
prompt: |
|
|
94
97
|
Create 2 social hashtags for this topic: {{ item }}
|
|
95
98
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
@@ -109,6 +109,8 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
109
109
|
observer=observer,
|
|
110
110
|
workflow_input=workflow_input,
|
|
111
111
|
).run()
|
|
112
|
+
except KeyboardInterrupt:
|
|
113
|
+
sys.exit(130)
|
|
112
114
|
except (ConfigError, ExecutionError) as exc:
|
|
113
115
|
_print_error(str(exc))
|
|
114
116
|
sys.exit(1)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from telize.config.models.actions import (
|
|
2
|
+
ChatStep,
|
|
2
3
|
FlowRefStep,
|
|
3
4
|
InputStep,
|
|
4
5
|
LlmStep,
|
|
@@ -13,6 +14,7 @@ from telize.config.models.flow import Flow
|
|
|
13
14
|
from telize.config.models.spec import WorkflowSpec
|
|
14
15
|
|
|
15
16
|
__all__ = [
|
|
17
|
+
"ChatStep",
|
|
16
18
|
"Flow",
|
|
17
19
|
"FlowRefStep",
|
|
18
20
|
"GlobalConfig",
|
|
@@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class LoopConfig(BaseModel):
|
|
9
|
-
"""Iterate
|
|
9
|
+
"""Iterate a step over items produced from a prior step's output."""
|
|
10
10
|
|
|
11
11
|
model_config = ConfigDict(extra="forbid")
|
|
12
12
|
|
|
@@ -14,12 +14,12 @@ class LoopConfig(BaseModel):
|
|
|
14
14
|
description="Jinja template resolving to a delimited list (e.g. `{{ steps.foo.output }}`).",
|
|
15
15
|
)
|
|
16
16
|
split_by: str = Field(
|
|
17
|
-
default="
|
|
17
|
+
default="\n<|separator|>\n",
|
|
18
18
|
description="Delimiter used to split `items` into separate loop iterations.",
|
|
19
19
|
)
|
|
20
|
-
|
|
21
|
-
default="
|
|
22
|
-
description="
|
|
20
|
+
separator: str = Field(
|
|
21
|
+
default="\n<|separator|>\n",
|
|
22
|
+
description="String inserted between each iteration's output when joining results.",
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
@@ -30,6 +30,10 @@ class DirectoryInput(BaseModel):
|
|
|
30
30
|
|
|
31
31
|
path: str
|
|
32
32
|
include: str = Field(default="*", description="Glob pattern for files to include.")
|
|
33
|
+
separator: str = Field(
|
|
34
|
+
default="\n<|separator|>\n",
|
|
35
|
+
description="String inserted between each file section when joining.",
|
|
36
|
+
)
|
|
33
37
|
|
|
34
38
|
|
|
35
39
|
class _StepBase(BaseModel):
|
|
@@ -41,6 +45,17 @@ class _StepBase(BaseModel):
|
|
|
41
45
|
min_length=1,
|
|
42
46
|
description="Unique step id within the flow; referenced as `steps.<name>.output`.",
|
|
43
47
|
)
|
|
48
|
+
output_to: str | None = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Optional path to write raw step output when the step completes.",
|
|
51
|
+
)
|
|
52
|
+
loop: LoopConfig | None = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description=(
|
|
55
|
+
"Optional loop config; runs the step once per item, exposing the "
|
|
56
|
+
"current value as `{{ item }}` and joining outputs with `separator`."
|
|
57
|
+
),
|
|
58
|
+
)
|
|
44
59
|
|
|
45
60
|
|
|
46
61
|
class InputStep(_StepBase):
|
|
@@ -68,11 +83,6 @@ class LlmStep(_StepBase):
|
|
|
68
83
|
description="Name of a model defined in the top-level `models` mapping.",
|
|
69
84
|
)
|
|
70
85
|
prompt: str
|
|
71
|
-
output_to: str | None = Field(
|
|
72
|
-
default=None,
|
|
73
|
-
description="Optional path to write raw output after the step completes.",
|
|
74
|
-
)
|
|
75
|
-
loop: LoopConfig | None = None
|
|
76
86
|
|
|
77
87
|
|
|
78
88
|
class ShellStep(_StepBase):
|
|
@@ -106,6 +116,16 @@ class FlowRefStep(_StepBase):
|
|
|
106
116
|
run: str = Field(description="Name of the flow to execute.")
|
|
107
117
|
|
|
108
118
|
|
|
119
|
+
class ChatStep(_StepBase):
|
|
120
|
+
"""Prompt the user for input interactively in the terminal."""
|
|
121
|
+
|
|
122
|
+
uses: Literal["chat"] = "chat"
|
|
123
|
+
message: str = Field(
|
|
124
|
+
default="",
|
|
125
|
+
description="Optional message shown before collecting user input (supports Jinja).",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
109
129
|
class YamlStep(_StepBase):
|
|
110
130
|
"""Run a workflow defined in an external YAML file."""
|
|
111
131
|
|
|
@@ -123,6 +143,6 @@ class YamlStep(_StepBase):
|
|
|
123
143
|
|
|
124
144
|
|
|
125
145
|
Step = Annotated[
|
|
126
|
-
InputStep | LlmStep | ShellStep | PythonStep | FlowRefStep | YamlStep,
|
|
146
|
+
InputStep | LlmStep | ShellStep | PythonStep | FlowRefStep | ChatStep | YamlStep,
|
|
127
147
|
Field(discriminator="uses"),
|
|
128
148
|
]
|