andon-ai 0.1.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.
Files changed (48) hide show
  1. andon_ai-0.1.0/.gitignore +50 -0
  2. andon_ai-0.1.0/AGENTS.md +1 -0
  3. andon_ai-0.1.0/CLAUDE.md +122 -0
  4. andon_ai-0.1.0/PKG-INFO +244 -0
  5. andon_ai-0.1.0/README.md +233 -0
  6. andon_ai-0.1.0/andon_cli/__init__.py +7 -0
  7. andon_ai-0.1.0/andon_cli/__main__.py +5 -0
  8. andon_ai-0.1.0/andon_cli/api.py +167 -0
  9. andon_ai-0.1.0/andon_cli/input_files.py +219 -0
  10. andon_ai-0.1.0/andon_cli/main.py +900 -0
  11. andon_ai-0.1.0/andon_cli/workspace.py +122 -0
  12. andon_ai-0.1.0/andon_dsl/__init__.py +15 -0
  13. andon_ai-0.1.0/andon_dsl/_graph/__init__.py +57 -0
  14. andon_ai-0.1.0/andon_dsl/_graph/model.py +823 -0
  15. andon_ai-0.1.0/andon_dsl/_identity.py +17 -0
  16. andon_ai-0.1.0/andon_dsl/agents/__init__.py +35 -0
  17. andon_ai-0.1.0/andon_dsl/agents/context.py +257 -0
  18. andon_ai-0.1.0/andon_dsl/agents/core.py +312 -0
  19. andon_ai-0.1.0/andon_dsl/agents/settings.py +64 -0
  20. andon_ai-0.1.0/andon_dsl/agents/templates.py +29 -0
  21. andon_ai-0.1.0/andon_dsl/authoring.py +29 -0
  22. andon_ai-0.1.0/andon_dsl/docs/__init__.py +16 -0
  23. andon_ai-0.1.0/andon_dsl/docs/authoring.md +350 -0
  24. andon_ai-0.1.0/andon_dsl/errors.py +52 -0
  25. andon_ai-0.1.0/andon_dsl/integrations/__init__.py +31 -0
  26. andon_ai-0.1.0/andon_dsl/integrations/connections.py +278 -0
  27. andon_ai-0.1.0/andon_dsl/resources/__init__.py +32 -0
  28. andon_ai-0.1.0/andon_dsl/resources/artifacts.py +300 -0
  29. andon_ai-0.1.0/andon_dsl/resources/documents.py +32 -0
  30. andon_ai-0.1.0/andon_dsl/resources/files.py +181 -0
  31. andon_ai-0.1.0/andon_dsl/resources/reference_data.py +101 -0
  32. andon_ai-0.1.0/andon_dsl/resources/schema.py +11 -0
  33. andon_ai-0.1.0/andon_dsl/tools/__init__.py +35 -0
  34. andon_ai-0.1.0/andon_dsl/tools/catalog.py +110 -0
  35. andon_ai-0.1.0/andon_dsl/tools/core.py +134 -0
  36. andon_ai-0.1.0/andon_dsl/tools/stubs.py +209 -0
  37. andon_ai-0.1.0/andon_dsl/tools/toolsets.py +72 -0
  38. andon_ai-0.1.0/andon_dsl/tools/web.py +21 -0
  39. andon_ai-0.1.0/andon_dsl/validation/__init__.py +47 -0
  40. andon_ai-0.1.0/andon_dsl/validation/rules.py +6026 -0
  41. andon_ai-0.1.0/andon_dsl/workflows/__init__.py +40 -0
  42. andon_ai-0.1.0/andon_dsl/workflows/core.py +361 -0
  43. andon_ai-0.1.0/andon_dsl/workflows/durations.py +37 -0
  44. andon_ai-0.1.0/andon_dsl/workflows/primitives.py +647 -0
  45. andon_ai-0.1.0/andon_dsl/workflows/steps.py +353 -0
  46. andon_ai-0.1.0/andon_dsl/workspace/__init__.py +17 -0
  47. andon_ai-0.1.0/andon_dsl/workspace/template.py +265 -0
  48. andon_ai-0.1.0/pyproject.toml +41 -0
@@ -0,0 +1,50 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+
9
+ # Environment
10
+ .env
11
+ .env.*
12
+
13
+ # IDE
14
+ .vscode/*
15
+ !.vscode/settings.json
16
+ .idea/
17
+ .claude/
18
+
19
+ # OS
20
+ .DS_Store
21
+
22
+ # Testing
23
+ .pytest_cache/
24
+ .coverage
25
+ htmlcov/
26
+
27
+ # Node (frontend)
28
+ node_modules/
29
+ web/dist/
30
+
31
+ # Local storage data dirs for LocalFileService / LocalGitStore. Path
32
+ # depends on cwd: ``./storage`` from project root, ``./storage`` from
33
+ # backend/. Anchor each so we don't accidentally ignore Python
34
+ # packages named ``storage`` (e.g. ``backend/src/connections/storage/``
35
+ # for the S3 provider).
36
+ /storage/
37
+ /backend/storage/
38
+
39
+ # Logfire
40
+ .logfire/
41
+
42
+ # Large test assets (downloaded on demand)
43
+ backend/tests/assets/nvda-*
44
+
45
+ # denials triage demo patient documents are generated locally from anonymized seed data.
46
+ sdk/examples/denials_triage/andon/data/patient/
47
+
48
+ # Local demo run state.
49
+ .demo/
50
+ sdk/examples/denials_triage/.demo/
@@ -0,0 +1 @@
1
+ CLAUDE.md
@@ -0,0 +1,122 @@
1
+ # CLAUDE.md
2
+
3
+ Andon SDK is the public authoring surface for workflows, agents, tools,
4
+ connections, and the CLI used to validate and deploy them.
5
+
6
+ ## Documentation Ownership
7
+
8
+ - `README.md` is the release-facing introduction and tutorial. Keep its
9
+ examples small, executable, and limited to product capabilities offered to
10
+ authors.
11
+ - `andon_dsl/docs/authoring.md` is the exact workspace-authoring contract
12
+ shipped in the wheel and printed by `andon docs`. Put DSL rules, durability
13
+ semantics, limits, and sharp edges there.
14
+ - Platform tool stubs and their docstrings are the capability contract printed
15
+ by `andon tools`. Do not duplicate tool signatures or provider details in
16
+ the README or generated agent guidance.
17
+ - `andon_dsl/workspace/template.py` seeds the workspace `andon/AGENTS.md`. Keep
18
+ that guide concise and route coding agents to `andon docs` and `andon tools`
19
+ for version-matched contracts.
20
+ - `examples/` holds demo workspaces that live only in this repo; they are
21
+ excluded from the published package. Every example workflow must validate
22
+ and compile against the current SDK and be exercised by a test — fix or
23
+ delete an example rather than letting it drift.
24
+
25
+ ## Workflow Authoring
26
+
27
+ - Keep `@workflow`, `@step`, `@tool`, and `Agent(...)` declarations at module
28
+ scope. Agent declarations must be direct module-level assignments like
29
+ `extractor = Agent(...)` so deploy-time discovery can give them stable
30
+ identities.
31
+ - Workflow bodies describe durable orchestration. Use `branch(...)`, `map(...)`,
32
+ `loop(...)`, `wait_for_event(...)`, and `run_workflow(...)` for control flow;
33
+ put normal Python branching, loops, parsing, and API glue inside `@step`
34
+ bodies.
35
+ - Agent prompt templates are Handlebars over the typed `inputs` object
36
+ (computed fields included): `{{claim.patient.name}}` paths, `{{#if}}` /
37
+ `{{#each}}` blocks, and the `{{json field}}` helper for embedding a field
38
+ as pretty-printed JSON. Rendering is strict (a missing path fails the
39
+ run). Statically known call-site templates are validated against the
40
+ agent's `input_type` during deploy; every rendered template is validated
41
+ again at dispatch. The contract lives in `andon_dsl.agents.templates`.
42
+ Agent calls accept the same text/image/document `Prompt` shape as
43
+ `ctx.prompt`; rendering applies to text parts. Do not use Python
44
+ `str.format` braces in agent prompts; write a literal `{{` as `\{{`.
45
+ - `Agent(output_type=...)` and `Agent(output_schema_field=...)` are mutually
46
+ exclusive. `output_schema_field` names an input field whose value is a JSON
47
+ Schema dict for the full agent output. `output_type` may be a union; prefer a
48
+ discriminated union when variants share fields.
49
+ - `output_validators=[fn]` functions receive `(inputs, output)` after type or
50
+ schema validation. Raise `AgentRetryError` when the model should repair the
51
+ output. Return a replacement output to normalize it, or `None` to keep the
52
+ current value. Ordinary exceptions, including `ValueError`, are treated as
53
+ validator bugs and fail the run. Validators should be deterministic in
54
+ `(inputs, output)` because validation may re-run against a cached model
55
+ response during replay.
56
+ - Error types mean different things: `AgentRetryError` is feedback to the model
57
+ for tool calls and output validators; `StepRetryError` consumes the step
58
+ retry budget; `UserReadableError` fails with a user-safe message; ordinary
59
+ exceptions are internal failures. Use a typed agent result for expected
60
+ recoverable outcomes; `UserReadableError` is a terminal run failure rather
61
+ than step-level fallback control flow.
62
+ - `Agent(code_mode=True)` loads typed cell inputs through `get_inputs()` and
63
+ finalizes through `SUBMIT(result=...)`. Injected tools are keyword-only;
64
+ await those rendered as `async def` in the `run_code` catalog.
65
+ `get_inputs()` and `SUBMIT(...)` are synchronous. A plain text answer is not
66
+ a final structured result. `SUBMIT` runs declared type/schema checks
67
+ immediately; custom output validators run after submission while the agent
68
+ can still retry.
69
+ - Deployed workflow execution validates declared output contracts in the
70
+ sandbox, where the original user classes and validators exist. Runtime code
71
+ outside the artifact may see metadata-only specs for deployed tools and
72
+ validators, not live Python callables.
73
+
74
+ ## Tools And Files
75
+
76
+ - Use `@tool` for model-callable helpers. Tool bodies should raise
77
+ `AgentRetryError` only for bad model-supplied arguments the model can
78
+ repair (malformed input, an id the model invented). A legitimate miss
79
+ ("no catalog entry for this code") is a result, not an error: return an
80
+ empty list or `None` and put "an empty result is the final answer — do
81
+ not retry" guidance in the docstring. Retry feedback is budgeted by
82
+ `Agent(retries=N)`; a raise that fires on valid data can exhaust the
83
+ budget and fail the run on a normal domain outcome. Rule of thumb: an
84
+ `AgentRetryError` should be unreachable for a well-behaved model
85
+ operating on valid data.
86
+ - Platform tools in `andon_dsl.tools` are SDK stubs; their implementations run
87
+ in the platform runtime. Keep user-authored workflow logic in the workflow
88
+ package, not in platform stubs.
89
+ - Give agents `web_search`/`web_fetch` for web browsing. Use
90
+ `fetch_to_file_ref` when an external URL must become a `FileRef` for
91
+ document tools or later workflow steps. Large payload spillover belongs in
92
+ runtime payload handling, not in web browsing stubs.
93
+ - Put document `FileRef` fields on the agent's typed inputs. A `FileRef`
94
+ renders as its `andon://...` URI in prompt templates and context blocks;
95
+ tell the model to pass that URI unchanged to typed tool arguments such as
96
+ `read_document(file=...)`. File metadata and bytes stay behind the runtime
97
+ reference. Keep the workflow and agent fields typed as `FileRef`; the CLI
98
+ accepts local paths at those schema positions and uploads them before run
99
+ creation.
100
+ - `StrategyFile(...)` paths resolve relative to the file that defines the
101
+ agent and must point to markdown files under `andon/prompts`.
102
+
103
+ ## Validation
104
+
105
+ - Promote invariants into the SDK-time validator whenever the artifact tree
106
+ carries enough information to check them.
107
+ - Keep executable-body validation source-only. Resolve step/tool names with
108
+ Python lexical scoping, require workspace imports to resolve inside the
109
+ deployed tree, reject wildcard and platform-internal imports, and leave
110
+ third-party package availability to `andon.toml` `[sandbox] packages`.
111
+ - Workflow primitives run only in `@workflow` bodies. User-authored `@step`
112
+ and `@tool` contexts expose `connect`, `prompt`, artifact I/O, and document
113
+ reads; validate direct context-member calls against that runtime surface.
114
+ - Extend learning and evaluation capabilities through compile-discovered named
115
+ code artifacts or platform stores keyed by structured definition, call-site,
116
+ and execution references. Keep domain semantics such as metrics, confidence,
117
+ verdicts, corrections, and datasets out of workflow IR node types.
118
+ - Keep source coordinates on validation errors: file, module path, binding or
119
+ function name, and line.
120
+ - When a step or tool footgun recurs, constrain its body shape at validation
121
+ time or add an explicit DSL primitive instead of leaving it to fail in the
122
+ sandbox.
@@ -0,0 +1,244 @@
1
+ Metadata-Version: 2.4
2
+ Name: andon-ai
3
+ Version: 0.1.0
4
+ Summary: Andon SDK and CLI for authoring, deploying, and running workflows
5
+ Requires-Python: >=3.13
6
+ Requires-Dist: httpx>=0.28
7
+ Requires-Dist: packaging>=24.0
8
+ Requires-Dist: pydantic>=2.0
9
+ Requires-Dist: typing-extensions>=4.15
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Andon SDK and CLI (`andon-ai`)
13
+
14
+ Andon is a Python SDK for building durable, document-centric workflows with
15
+ typed steps, LLM agents, human review, and integrations. Authors define the
16
+ workflow; the Andon platform handles execution, checkpointing, files, and
17
+ operations.
18
+
19
+ Installing `andon-ai` provides the `andon` command and the `andon_dsl` Python
20
+ package. Python 3.13 or newer and [uv](https://docs.astral.sh/uv/) are required.
21
+
22
+ ## Create a workspace
23
+
24
+ Start in an empty directory:
25
+
26
+ ```bash
27
+ mkdir claims-workflow
28
+ cd claims-workflow
29
+ uvx andon-ai init
30
+ uv sync
31
+ ```
32
+
33
+ `andon init` creates `andon.toml`, a deployable `andon/` package, a sample
34
+ workflow and test, and local project configuration. It preserves files that
35
+ already exist, so an empty directory is the supported starting point.
36
+
37
+ The generated `AGENTS.md` routes coding agents to the authoring contract and
38
+ tool catalog that match the installed SDK.
39
+
40
+ ## Build an email workflow
41
+
42
+ This workflow reads unread Gmail messages, summarizes them with an agent, and
43
+ emails the digest. Save it as `andon/workflows/inbox.py`:
44
+
45
+ ```python
46
+ from dataclasses import dataclass
47
+
48
+ from andon_dsl.agents import Agent, StepContext
49
+ from andon_dsl.integrations import EmailFilter, EmailMessage, Gmail
50
+ from andon_dsl.workflows import map, step, workflow
51
+
52
+
53
+ @dataclass
54
+ class InboxInput:
55
+ recipient: str
56
+ limit: int = 10
57
+
58
+
59
+ @dataclass
60
+ class EmailSummary:
61
+ sender: str
62
+ subject: str
63
+ summary: str
64
+
65
+
66
+ summarizer = Agent(
67
+ model_family="small",
68
+ input_type=EmailMessage,
69
+ output_type=EmailSummary,
70
+ system_instructions="Summarize inbound email clearly and concisely.",
71
+ )
72
+
73
+
74
+ @step(connections=["gmail"])
75
+ async def read_inbox(ctx: StepContext, input: InboxInput) -> list[EmailMessage]:
76
+ gmail = await ctx.connect(Gmail, "gmail")
77
+ return await gmail.list_messages(
78
+ filter=EmailFilter(is_unread=True),
79
+ limit=input.limit,
80
+ )
81
+
82
+
83
+ @step
84
+ async def summarize(message: EmailMessage) -> EmailSummary:
85
+ return await summarizer(
86
+ "Summarize this email from {{sender}}.\n"
87
+ "Subject: {{subject}}\n\n"
88
+ "{{body_text}}",
89
+ inputs=message,
90
+ )
91
+
92
+
93
+ @step(connections=["gmail"])
94
+ async def send_digest(
95
+ ctx: StepContext,
96
+ recipient: str,
97
+ summaries: list[EmailSummary],
98
+ ) -> str:
99
+ gmail = await ctx.connect(Gmail, "gmail")
100
+ body = "\n\n".join(
101
+ f"{item.subject} — {item.sender}\n{item.summary}" for item in summaries
102
+ )
103
+ return await gmail.send(
104
+ to=[recipient],
105
+ subject="Andon inbox digest",
106
+ body=body or "No unread messages.",
107
+ )
108
+
109
+
110
+ @workflow()
111
+ def process_inbox(input: InboxInput) -> str:
112
+ messages = read_inbox(input)
113
+ summaries = map(summarize, messages)
114
+ return send_digest(input.recipient, summaries)
115
+ ```
116
+
117
+ Declare the workflow in `andon.toml`:
118
+
119
+ ```toml
120
+ [[workflows]]
121
+ name = "process_inbox"
122
+ path = "andon/workflows/inbox.py"
123
+ ```
124
+
125
+ The connection name passed to `ctx.connect()` refers to Gmail credentials
126
+ configured for the current Andon organization. The same name must appear in
127
+ the step's `connections=[...]` allow-list.
128
+
129
+ ## Core concepts
130
+
131
+ - **Workflows** are declarative graphs of steps and control-flow primitives.
132
+ Their bodies are traced during deployment and do not run as ordinary Python
133
+ during workflow execution.
134
+ - **Steps** are typed Python functions and the durability boundary. Successful
135
+ results are checkpointed; external side effects should be safe to repeat if
136
+ an interrupted attempt runs again.
137
+ - **Agents** are typed LLM-powered components declared at module scope and
138
+ awaited inside steps. Runtime prompts are Handlebars templates over the
139
+ agent's typed inputs.
140
+ - **Tools and toolsets** give agents explicitly selected capabilities. Andon
141
+ provides platform tools and curated toolsets, and authors can define their
142
+ own model-callable functions with `@tool`.
143
+ - **Connections** provide typed access to organization-configured email through
144
+ the Gmail protocol without exposing credentials to workflow code.
145
+ - **FileRef** values represent uploaded files and generated artifacts. Keep
146
+ documents and large intermediate outputs behind `FileRef` rather than
147
+ passing their bytes or full text through step results.
148
+
149
+ Workflow bodies use primitives such as `map`, `parallel`, `branch`, `loop`,
150
+ `wait_for_event`, `wait_for_review`, `sleep`, and `run_workflow`. Put ordinary
151
+ Python branching, iteration, parsing, and integration glue inside steps.
152
+
153
+ ## Tools and toolsets
154
+
155
+ Platform tools and curated toolsets are imported from `andon_dsl.tools` and
156
+ opted into an agent through `tools=[...]`. Authors can combine them with their
157
+ own `@tool` functions:
158
+
159
+ ```python
160
+ from andon_dsl.agents import Agent
161
+ from andon_dsl.tools import tool
162
+ from andon_dsl.tools.toolsets import document_analysis
163
+
164
+
165
+ @tool
166
+ def normalize_vendor_name(name: str) -> str:
167
+ """Return a normalized vendor name for matching."""
168
+ return " ".join(name.lower().split())
169
+
170
+
171
+ analyst = Agent(
172
+ tools=[*document_analysis.tools, normalize_vendor_name],
173
+ )
174
+ ```
175
+
176
+ The installed SDK is the source of truth for platform capabilities:
177
+
178
+ ```bash
179
+ uv run andon tools # print tools, toolsets, signatures, and descriptions
180
+ uv run andon tools --json # emit the same catalog as structured JSON
181
+ ```
182
+
183
+ ## Validate, deploy, and run
184
+
185
+ An organization admin creates API keys in the console's
186
+ [Settings page](https://app.andonai.com/settings). Keys carry a role:
187
+ `admin` keys can deploy and activate; `operator` keys can start and watch
188
+ runs. Expose the key to the CLI:
189
+
190
+ ```bash
191
+ export ANDON_API_KEY="ak-..."
192
+ ```
193
+
194
+ The CLI uses `https://app.andonai.com/` by default. Set `ANDON_API_URL` only
195
+ when targeting a different Andon environment.
196
+
197
+ ```bash
198
+ uv run andon validate
199
+ uv run pytest
200
+ uv run andon deploy --no-activate
201
+ uv run andon run process_inbox \
202
+ --deployment-id <deployment-id> \
203
+ --input-json '{"recipient":"ops@example.com","limit":10}'
204
+ uv run andon runs watch <run-id>
205
+ ```
206
+
207
+ `andon validate` performs local manifest and static source validation.
208
+ `andon deploy` publishes the full local `andon.toml` plus `andon/` snapshot,
209
+ compiles and type-checks its workflows, and activates the deployment unless
210
+ `--no-activate` is passed. Publishing replaces the remote workspace snapshot,
211
+ so remote files absent from the local tree are deleted.
212
+
213
+ `andon run` starts a deployed workflow. Local paths supplied at typed
214
+ `FileRef` input positions are uploaded before run creation.
215
+
216
+ ## Authoring reference
217
+
218
+ Use the references bundled with the installed SDK before editing a workspace:
219
+
220
+ ```bash
221
+ uv run andon docs
222
+ uv run andon tools
223
+ ```
224
+
225
+ Here `uv run` executes a command in the workspace environment, while
226
+ `andon docs` prints the complete, version-matched authoring contract to the
227
+ terminal. It is separate from `andon run <workflow>`, which starts a workflow
228
+ run.
229
+
230
+ The authoring contract covers workflow restrictions, primitives, durable
231
+ identity, retries, agent settings, files, reference data, testing, and other
232
+ sharp edges. The generated `andon/AGENTS.md` points coding agents to this
233
+ contract and the installed tool catalog.
234
+
235
+ ## Public imports
236
+
237
+ | Package | Purpose |
238
+ |---|---|
239
+ | `andon_dsl.workflows` | Workflow and step decorators plus control-flow primitives. |
240
+ | `andon_dsl.agents` | Agent declarations, prompt content, contexts, model settings, and usage limits. |
241
+ | `andon_dsl.tools` | User-authored tools and platform tool stubs; curated bundles live in `andon_dsl.tools.toolsets`. |
242
+ | `andon_dsl.resources` | `FileRef`, document result types, reference data helpers, and schema extensions. |
243
+ | `andon_dsl.integrations` | The Gmail connection protocol and shared email types for `ctx.connect()`. |
244
+ | `andon_dsl.errors` | Public authoring and execution error types. |
@@ -0,0 +1,233 @@
1
+ # Andon SDK and CLI (`andon-ai`)
2
+
3
+ Andon is a Python SDK for building durable, document-centric workflows with
4
+ typed steps, LLM agents, human review, and integrations. Authors define the
5
+ workflow; the Andon platform handles execution, checkpointing, files, and
6
+ operations.
7
+
8
+ Installing `andon-ai` provides the `andon` command and the `andon_dsl` Python
9
+ package. Python 3.13 or newer and [uv](https://docs.astral.sh/uv/) are required.
10
+
11
+ ## Create a workspace
12
+
13
+ Start in an empty directory:
14
+
15
+ ```bash
16
+ mkdir claims-workflow
17
+ cd claims-workflow
18
+ uvx andon-ai init
19
+ uv sync
20
+ ```
21
+
22
+ `andon init` creates `andon.toml`, a deployable `andon/` package, a sample
23
+ workflow and test, and local project configuration. It preserves files that
24
+ already exist, so an empty directory is the supported starting point.
25
+
26
+ The generated `AGENTS.md` routes coding agents to the authoring contract and
27
+ tool catalog that match the installed SDK.
28
+
29
+ ## Build an email workflow
30
+
31
+ This workflow reads unread Gmail messages, summarizes them with an agent, and
32
+ emails the digest. Save it as `andon/workflows/inbox.py`:
33
+
34
+ ```python
35
+ from dataclasses import dataclass
36
+
37
+ from andon_dsl.agents import Agent, StepContext
38
+ from andon_dsl.integrations import EmailFilter, EmailMessage, Gmail
39
+ from andon_dsl.workflows import map, step, workflow
40
+
41
+
42
+ @dataclass
43
+ class InboxInput:
44
+ recipient: str
45
+ limit: int = 10
46
+
47
+
48
+ @dataclass
49
+ class EmailSummary:
50
+ sender: str
51
+ subject: str
52
+ summary: str
53
+
54
+
55
+ summarizer = Agent(
56
+ model_family="small",
57
+ input_type=EmailMessage,
58
+ output_type=EmailSummary,
59
+ system_instructions="Summarize inbound email clearly and concisely.",
60
+ )
61
+
62
+
63
+ @step(connections=["gmail"])
64
+ async def read_inbox(ctx: StepContext, input: InboxInput) -> list[EmailMessage]:
65
+ gmail = await ctx.connect(Gmail, "gmail")
66
+ return await gmail.list_messages(
67
+ filter=EmailFilter(is_unread=True),
68
+ limit=input.limit,
69
+ )
70
+
71
+
72
+ @step
73
+ async def summarize(message: EmailMessage) -> EmailSummary:
74
+ return await summarizer(
75
+ "Summarize this email from {{sender}}.\n"
76
+ "Subject: {{subject}}\n\n"
77
+ "{{body_text}}",
78
+ inputs=message,
79
+ )
80
+
81
+
82
+ @step(connections=["gmail"])
83
+ async def send_digest(
84
+ ctx: StepContext,
85
+ recipient: str,
86
+ summaries: list[EmailSummary],
87
+ ) -> str:
88
+ gmail = await ctx.connect(Gmail, "gmail")
89
+ body = "\n\n".join(
90
+ f"{item.subject} — {item.sender}\n{item.summary}" for item in summaries
91
+ )
92
+ return await gmail.send(
93
+ to=[recipient],
94
+ subject="Andon inbox digest",
95
+ body=body or "No unread messages.",
96
+ )
97
+
98
+
99
+ @workflow()
100
+ def process_inbox(input: InboxInput) -> str:
101
+ messages = read_inbox(input)
102
+ summaries = map(summarize, messages)
103
+ return send_digest(input.recipient, summaries)
104
+ ```
105
+
106
+ Declare the workflow in `andon.toml`:
107
+
108
+ ```toml
109
+ [[workflows]]
110
+ name = "process_inbox"
111
+ path = "andon/workflows/inbox.py"
112
+ ```
113
+
114
+ The connection name passed to `ctx.connect()` refers to Gmail credentials
115
+ configured for the current Andon organization. The same name must appear in
116
+ the step's `connections=[...]` allow-list.
117
+
118
+ ## Core concepts
119
+
120
+ - **Workflows** are declarative graphs of steps and control-flow primitives.
121
+ Their bodies are traced during deployment and do not run as ordinary Python
122
+ during workflow execution.
123
+ - **Steps** are typed Python functions and the durability boundary. Successful
124
+ results are checkpointed; external side effects should be safe to repeat if
125
+ an interrupted attempt runs again.
126
+ - **Agents** are typed LLM-powered components declared at module scope and
127
+ awaited inside steps. Runtime prompts are Handlebars templates over the
128
+ agent's typed inputs.
129
+ - **Tools and toolsets** give agents explicitly selected capabilities. Andon
130
+ provides platform tools and curated toolsets, and authors can define their
131
+ own model-callable functions with `@tool`.
132
+ - **Connections** provide typed access to organization-configured email through
133
+ the Gmail protocol without exposing credentials to workflow code.
134
+ - **FileRef** values represent uploaded files and generated artifacts. Keep
135
+ documents and large intermediate outputs behind `FileRef` rather than
136
+ passing their bytes or full text through step results.
137
+
138
+ Workflow bodies use primitives such as `map`, `parallel`, `branch`, `loop`,
139
+ `wait_for_event`, `wait_for_review`, `sleep`, and `run_workflow`. Put ordinary
140
+ Python branching, iteration, parsing, and integration glue inside steps.
141
+
142
+ ## Tools and toolsets
143
+
144
+ Platform tools and curated toolsets are imported from `andon_dsl.tools` and
145
+ opted into an agent through `tools=[...]`. Authors can combine them with their
146
+ own `@tool` functions:
147
+
148
+ ```python
149
+ from andon_dsl.agents import Agent
150
+ from andon_dsl.tools import tool
151
+ from andon_dsl.tools.toolsets import document_analysis
152
+
153
+
154
+ @tool
155
+ def normalize_vendor_name(name: str) -> str:
156
+ """Return a normalized vendor name for matching."""
157
+ return " ".join(name.lower().split())
158
+
159
+
160
+ analyst = Agent(
161
+ tools=[*document_analysis.tools, normalize_vendor_name],
162
+ )
163
+ ```
164
+
165
+ The installed SDK is the source of truth for platform capabilities:
166
+
167
+ ```bash
168
+ uv run andon tools # print tools, toolsets, signatures, and descriptions
169
+ uv run andon tools --json # emit the same catalog as structured JSON
170
+ ```
171
+
172
+ ## Validate, deploy, and run
173
+
174
+ An organization admin creates API keys in the console's
175
+ [Settings page](https://app.andonai.com/settings). Keys carry a role:
176
+ `admin` keys can deploy and activate; `operator` keys can start and watch
177
+ runs. Expose the key to the CLI:
178
+
179
+ ```bash
180
+ export ANDON_API_KEY="ak-..."
181
+ ```
182
+
183
+ The CLI uses `https://app.andonai.com/` by default. Set `ANDON_API_URL` only
184
+ when targeting a different Andon environment.
185
+
186
+ ```bash
187
+ uv run andon validate
188
+ uv run pytest
189
+ uv run andon deploy --no-activate
190
+ uv run andon run process_inbox \
191
+ --deployment-id <deployment-id> \
192
+ --input-json '{"recipient":"ops@example.com","limit":10}'
193
+ uv run andon runs watch <run-id>
194
+ ```
195
+
196
+ `andon validate` performs local manifest and static source validation.
197
+ `andon deploy` publishes the full local `andon.toml` plus `andon/` snapshot,
198
+ compiles and type-checks its workflows, and activates the deployment unless
199
+ `--no-activate` is passed. Publishing replaces the remote workspace snapshot,
200
+ so remote files absent from the local tree are deleted.
201
+
202
+ `andon run` starts a deployed workflow. Local paths supplied at typed
203
+ `FileRef` input positions are uploaded before run creation.
204
+
205
+ ## Authoring reference
206
+
207
+ Use the references bundled with the installed SDK before editing a workspace:
208
+
209
+ ```bash
210
+ uv run andon docs
211
+ uv run andon tools
212
+ ```
213
+
214
+ Here `uv run` executes a command in the workspace environment, while
215
+ `andon docs` prints the complete, version-matched authoring contract to the
216
+ terminal. It is separate from `andon run <workflow>`, which starts a workflow
217
+ run.
218
+
219
+ The authoring contract covers workflow restrictions, primitives, durable
220
+ identity, retries, agent settings, files, reference data, testing, and other
221
+ sharp edges. The generated `andon/AGENTS.md` points coding agents to this
222
+ contract and the installed tool catalog.
223
+
224
+ ## Public imports
225
+
226
+ | Package | Purpose |
227
+ |---|---|
228
+ | `andon_dsl.workflows` | Workflow and step decorators plus control-flow primitives. |
229
+ | `andon_dsl.agents` | Agent declarations, prompt content, contexts, model settings, and usage limits. |
230
+ | `andon_dsl.tools` | User-authored tools and platform tool stubs; curated bundles live in `andon_dsl.tools.toolsets`. |
231
+ | `andon_dsl.resources` | `FileRef`, document result types, reference data helpers, and schema extensions. |
232
+ | `andon_dsl.integrations` | The Gmail connection protocol and shared email types for `ctx.connect()`. |
233
+ | `andon_dsl.errors` | Public authoring and execution error types. |
@@ -0,0 +1,7 @@
1
+ """Andon workflow authoring CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __all__ = ["__version__"]
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from andon_cli.main import entrypoint
4
+
5
+ entrypoint()