roboz 0.1.2.dev4__tar.gz → 0.1.2.dev6__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 (75) hide show
  1. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/CHANGELOG.md +79 -0
  2. roboz-0.1.2.dev6/PKG-INFO +270 -0
  3. roboz-0.1.2.dev6/README.md +241 -0
  4. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/pyproject.toml +1 -1
  5. roboz-0.1.2.dev6/src/roboz/__init__.py +48 -0
  6. roboz-0.1.2.dev6/src/roboz/__init__.pyi +20 -0
  7. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/__init__.py +6 -1
  8. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/background_agent.py +23 -13
  9. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/core.py +15 -13
  10. roboz-0.1.2.dev6/src/roboz/agent/prompt_agent_tool.py +57 -0
  11. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/subagent.py +5 -9
  12. roboz-0.1.2.dev6/src/roboz/dependencies.py +122 -0
  13. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/deployment.py +21 -6
  14. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/__init__.py +3 -1
  15. roboz-0.1.2.dev6/src/roboz/llm/binding.py +86 -0
  16. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/calls.py +23 -17
  17. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/endpoints.py +173 -25
  18. roboz-0.1.2.dev6/src/roboz/llm/openai_compatible.py +144 -0
  19. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/openrouter.py +6 -21
  20. roboz-0.1.2.dev6/src/roboz/tooling/__init__.py +14 -0
  21. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tooling/_protocols.py +11 -4
  22. roboz-0.1.2.dev6/src/roboz/tooling/context.py +39 -0
  23. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tooling/core.py +44 -29
  24. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tooling/decorators.py +13 -6
  25. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tools/interaction.py +7 -15
  26. roboz-0.1.2.dev4/PKG-INFO +0 -218
  27. roboz-0.1.2.dev4/README.md +0 -189
  28. roboz-0.1.2.dev4/src/roboz/__init__.py +0 -91
  29. roboz-0.1.2.dev4/src/roboz/agent/prompt_agent_tool.py +0 -37
  30. roboz-0.1.2.dev4/src/roboz/dependencies.py +0 -297
  31. roboz-0.1.2.dev4/src/roboz/llm/binding.py +0 -150
  32. roboz-0.1.2.dev4/src/roboz/tooling/__init__.py +0 -6
  33. roboz-0.1.2.dev4/src/roboz/tooling/context.py +0 -101
  34. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/.gitignore +0 -0
  35. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/LICENSE +0 -0
  36. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/_naming.py +0 -0
  37. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/_execution_context.py +0 -0
  38. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/_identifiers.py +0 -0
  39. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/_notifications.py +0 -0
  40. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/_prompts.py +0 -0
  41. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/agent/_tool_observer.py +0 -0
  42. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/exceptions.py +0 -0
  43. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/_diagnostics.py +0 -0
  44. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/_retry.py +0 -0
  45. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/_truncation.py +0 -0
  46. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/completion.py +0 -0
  47. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/llm/prompts.py +0 -0
  48. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/__init__.py +0 -0
  49. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/_schema.py +0 -0
  50. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/_serialization.py +0 -0
  51. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/_telemetry.py +0 -0
  52. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/core.py +0 -0
  53. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/models/truncation.py +0 -0
  54. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/py.typed +0 -0
  55. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/__init__.py +0 -0
  56. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/_environment.py +0 -0
  57. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/_external.py +0 -0
  58. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/_logging.py +0 -0
  59. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/_paths.py +0 -0
  60. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/events.py +0 -0
  61. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/io.py +0 -0
  62. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/observability.py +0 -0
  63. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/persistence/__init__.py +0 -0
  64. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/persistence/activity.py +0 -0
  65. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/persistence/schema.py +0 -0
  66. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/pipe.py +0 -0
  67. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/runtime/sinks.py +0 -0
  68. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/skill/__init__.py +0 -0
  69. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/skill/_prompts.py +0 -0
  70. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/skill/core.py +0 -0
  71. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tooling/_prompts.py +0 -0
  72. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tooling/_typing.py +0 -0
  73. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tools/__init__.py +0 -0
  74. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tools/_identifiers.py +0 -0
  75. {roboz-0.1.2.dev4 → roboz-0.1.2.dev6}/src/roboz/tools/control.py +0 -0
@@ -2,6 +2,85 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.2.dev6 - 2026-09-15
6
+
7
+ - Breaking: make the `roboz` root a lazy authoring facade. It now exports only
8
+ `Agent`, `Skill`, `Tool`, `Factory`, `tool`, and `factory` alongside discoverable
9
+ domain namespaces. Import models from `roboz.models`, agent helpers from
10
+ `roboz.agent`, built-in tools from `roboz.tools`, and context protocols from
11
+ `roboz.tooling`. See [the import migration guide](docs/imports.md).
12
+
13
+ ## 0.1.2.dev5 - 2026-09-13
14
+
15
+ - Add `LLMEndpointRoute`, a typed live-selection layer above concrete chat
16
+ endpoints. Routes retain a caller-owned endpoint getter, report the current
17
+ selected resource without initializing clients, and resolve once per model
18
+ operation so in-flight calls retain their endpoint. Request and OpenRouter
19
+ policies support routes while keeping fixed endpoint use unchanged.
20
+
21
+ - Inspect a configured deployment with `DeployableAgent.external_dependencies()`.
22
+ It builds fresh, unstarted agents without event sinks and delegates to their
23
+ existing tool inspection, including child agents and skill resources. Capability
24
+ construction still runs normally; no additional dependency declaration is required.
25
+
26
+ - Initialize factory contexts lazily on invocation through the optional
27
+ `Materializable.materialize() -> Self` protocol. Binding, copying, and inspection
28
+ stay side-effect free. Endpoints support explicit early `materialize()` calls
29
+ while preserving their identity; prompt contexts delegate initialization.
30
+ Breaking: OpenAI-compatible client protocols now require `close() -> None` for
31
+ typed cleanup. See [the lifecycle contract](docs/dependency-primitives.md).
32
+
33
+ - Make resource-inspection declarations explicit: aggregate contexts and agents
34
+ implement the `HasExternalDependencies` protocol, renamed from `Context` with
35
+ no compatibility alias. Authors can inherit it to require
36
+ `external_dependencies()`; missing implementations fail type checking and
37
+ instantiation. Plain contexts remain unrestricted, and direct resources inherit
38
+ inspection from `ExternalDependency`.
39
+
40
+ - Breaking: migrate core interaction and agent factories to concrete contexts.
41
+ Bind interaction factories to strings, `run_subagent` to the child `Agent`,
42
+ and background/prompt factories to `BackgroundAgentContext`/`PromptAgentContext`
43
+ from `roboz.agent`. Background constructors own fresh state; rebinding and copies
44
+ share supplied state. Agent inspection uses live tool methods, and deployment
45
+ builders use the same bindings. Restore top-level agent, skill, and built-in
46
+ tool exports; removed dependency and `Ctx` APIs stay removed. See
47
+ [the primitive migration](docs/dependency-primitives.md).
48
+
49
+ - Breaking: core endpoints require synchronous OpenAI-compatible clients instead
50
+ of an untyped client. Client methods and request controls are checked statically;
51
+ the real `openai.OpenAI` client satisfies the protocols without a wrapper or an
52
+ SDK dependency in core. Replace placeholder or incompatible clients with a
53
+ conforming chat/transcription client. See [the client contract](docs/dependency-primitives.md).
54
+
55
+ - Breaking: external resource implementations must provide `check() -> bool` for
56
+ explicit availability checks. Executables check PATH; core endpoints use model
57
+ discovery without generating output. Results are uncached, absent resources
58
+ return `False`, and check errors propagate. Binding, copying, and inspection
59
+ never invoke checks. Plain contexts need no check method. See
60
+ [resource inspection and availability](docs/dependency-primitives.md).
61
+
62
+ - Accept any concretely typed factory context, including plain objects and lists.
63
+ Contexts without resource inspection are passed through unchanged and their
64
+ tools report no dependencies. Wrong context types remain static binding errors.
65
+
66
+ - Bind core chat and transcription endpoints directly as typed factory contexts,
67
+ retaining their identity and client for execution and inspection. Endpoint
68
+ request helpers and the selector now use concrete endpoints; lazy construction
69
+ and companion migrations remain deferred. Scripted endpoints report no external
70
+ resources. See [typed contexts and resource inspection](docs/dependency-primitives.md).
71
+ - Fix `@factory()` input inference so parenthesized factories retain the same
72
+ concrete input, output, and context types as bare `@factory` declarations.
73
+
74
+ - Breaking checkpoint: bind factories directly to concrete typed resources or
75
+ contexts with optional `external_dependencies()`, preserving the supplied object and
76
+ inspecting it live. Replace `Ctx` and tool dependency properties with concrete
77
+ contexts and `tool.external_dependencies()`. Dependency extension primitives
78
+ stay in `roboz.dependencies`; the top-level API now exposes only data and
79
+ tool/factory/context primitives. Remove legacy dependency bases, lazy/reference
80
+ helpers, and checker registration. Agent, built-in tool, and companion consumers
81
+ remain unmigrated; this checkpoint is not release-ready. See [typed contexts and resource inspection](docs/dependency-primitives.md)
82
+ for the contract, removed APIs, and migration boundary.
83
+
5
84
  ## 0.1.2.dev4 - 2026-09-12
6
85
 
7
86
  - Breaking: make `DeployableAgent` an explicitly configured class. Constructor
@@ -0,0 +1,270 @@
1
+ Metadata-Version: 2.5
2
+ Name: roboz
3
+ Version: 0.1.2.dev6
4
+ Import-Name: roboz
5
+ Summary: Typed primitives for composable agentic workflows
6
+ Project-URL: Homepage, https://github.com/Tachion-Oy/roboz
7
+ Project-URL: Repository, https://github.com/Tachion-Oy/roboz
8
+ Project-URL: Issues, https://github.com/Tachion-Oy/roboz/issues
9
+ Project-URL: Documentation, https://github.com/Tachion-Oy/roboz/tree/main/docs
10
+ Author: Tachion Oy
11
+ License-Expression: Apache-2.0
12
+ License-File: LICENSE
13
+ Keywords: agents,llm,tool-calling,typing,workflows
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.13
23
+ Requires-Dist: pydantic>=2.12.4
24
+ Requires-Dist: python-dotenv>=1.2.1
25
+ Requires-Dist: rich>=14.2.0
26
+ Provides-Extra: proton-bridge-beta
27
+ Requires-Dist: roboz-proton-bridge<0.2.0,>=0.1.0b1; extra == 'proton-bridge-beta'
28
+ Description-Content-Type: text/markdown
29
+
30
+ <div align="center">
31
+ <picture>
32
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/roboz-logo-dark.svg">
33
+ <source media="(prefers-color-scheme: light)" srcset="docs/assets/roboz-logo-light.svg">
34
+ <img alt="RoboZ" src="docs/assets/roboz-logo-dark.svg" width="560">
35
+ </picture>
36
+
37
+ <p><strong>Chain tools. Skip calls.</strong></p>
38
+ </div>
39
+
40
+ RoboZ is a framework for building llm powered agents. The core ingredient is that every tool can may be chained conditionally to a subsequent tool thus allowing easy injection of deterministic flows into agentic processes.
41
+
42
+ The package root contains the concise agent and tool authoring API. Models, LLM
43
+ operations, built-in tools, and runtime interfaces live in their corresponding
44
+ domain namespaces; see [public imports](docs/imports.md).
45
+
46
+ [![CI](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml/badge.svg)](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml)
47
+ [![Python 3.13+](https://img.shields.io/badge/Python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
49
+
50
+ > [!WARNING]
51
+ > RoboZ is pre-release software requiring Python 3.13 or newer. APIs may change
52
+ > before 1.0.
53
+
54
+ ## Basic idea
55
+
56
+ ![The usual agent loop sends every lunch-planning step back through the agent. A Roboz chain returns to the agent when Bob wants no lunch, passes any cuisine into one parameterized restaurant search, and retries the plan directly when no seats are available.](docs/assets/tool-chaining.svg)
57
+
58
+ ### Problems in agents: Context bloat and excessive back-and-forth
59
+ Suppose the task we want to achieve is ask our buddy Bob out to lunch and then book a table. For the sake of argument assume that our agent has access to the following MCP servers (Note: this is an example, RoboZ has native Tool primitives):
60
+
61
+ - Ask Bob what they want
62
+ - Find a restaurant
63
+ - Book a table.
64
+
65
+ In the usual approach an agent is presented each MCP server separately in the their system prompt and it must call them one-by-one to complete the task. When the agent is completing the task, at every turn it must choose the correct tool, formulate its output accordingly and absorb the reply into its context, which already must contain the specific instructions on how to use each tool. In addition, at each turn one has to wait for the llm to reply, each reply costs tokens and each reply risks a mistake from the llm.
66
+
67
+ ### Deterministic chains
68
+ The philosophy in RoboZ is that the workflow is deterministic an only choosing when to initiate is the agent's job. In RoboZ the agent would trigger the "ask Bob what they want" tool and all subsequent steps come by chaining: each tool is chained to other tools upstream and their output is passed down to the chained tool. Each link/edge may introduce a True/False condition, in this case for example if Bob interested in having lunch (with us). If he is not, RoboZ allows for the chain to break and returns back to the default tool, which for an agentic process is usually "ask the llm what to do next". The default mode is that chained tools are not presented to the agent, they are thus *passive* or in other words their role is strictly in forming deterministic workflows and they cannot be invoked.
69
+
70
+ ### Message truncation
71
+ Lengthy tasks with many tool calls also add many tokens in the context that may not be relevant to the end result. In RoboZ all tools may choose to truncate their message i.e. not show it to the agent in its complete form or only show it in its entirety a few times and then remove it from the agents context entirely, for example.
72
+
73
+
74
+
75
+
76
+
77
+ ## Code example
78
+ TBD
79
+
80
+
81
+ ```python
82
+ from roboz import tool
83
+ from roboz.models import Empty, Message
84
+
85
+
86
+ class LunchPreference(Empty):
87
+ cuisine: str | None
88
+
89
+
90
+ class Restaurant(Empty):
91
+ name: str
92
+ seats_available: bool
93
+
94
+
95
+ class Booking(Empty):
96
+ confirmation: str
97
+
98
+
99
+ @tool
100
+ def plan_lunch_with_bob(
101
+ input: Empty, messages: list[Message]
102
+ ) -> LunchPreference:
103
+ ...
104
+
105
+
106
+ @tool
107
+ def retry_plan_lunch_with_bob(
108
+ input: Restaurant, messages: list[Message]
109
+ ) -> LunchPreference:
110
+ ...
111
+
112
+
113
+ @tool(
114
+ chained_to=[plan_lunch_with_bob, retry_plan_lunch_with_bob],
115
+ chain_condition=lambda output: (
116
+ isinstance(output, LunchPreference)
117
+ and output.cuisine is not None
118
+ ),
119
+ )
120
+ def find_restaurant(
121
+ input: LunchPreference, messages: list[Message]
122
+ ) -> Restaurant:
123
+ ...
124
+
125
+
126
+ retry_plan_lunch_with_bob.chain(
127
+ chained_to=find_restaurant,
128
+ chain_condition=lambda output: (
129
+ isinstance(output, Restaurant) and not output.seats_available
130
+ ),
131
+ )
132
+
133
+
134
+ @tool(
135
+ chained_to=find_restaurant,
136
+ chain_condition=lambda output: (
137
+ isinstance(output, Restaurant) and output.seats_available
138
+ ),
139
+ )
140
+ def book_a_table(input: Restaurant, messages: list[Message]) -> Booking:
141
+ ...
142
+ ```
143
+
144
+ ## factory closure, endpoint instance and seeing the entire prompt
145
+ TBD
146
+
147
+
148
+ ## Try it
149
+
150
+ ```bash
151
+ uv add roboz
152
+ ```
153
+
154
+ Or with pip:
155
+
156
+ ```bash
157
+ python -m pip install roboz
158
+ ```
159
+
160
+ The complete [quick start](examples/quickstart.py) uses a deterministic mock
161
+ endpoint. Bob first chooses sushi; when no seats are available, the typed chain
162
+ retries the planner, routes his second choice to pizza, and books—all from one
163
+ model-selected entry into the chain and without credentials:
164
+
165
+ ```bash
166
+ uv run python examples/quickstart.py
167
+ ```
168
+
169
+ For an unpublished checkout, first run `uv sync --locked --dev`. PyPI commands
170
+ require a published release; see the [build and test guide](docs/build-and-test.md)
171
+ for local wheels.
172
+
173
+ ## Control what reaches the model
174
+
175
+ Context is a projection, not an ever-growing transcript. Every `Message` can
176
+ carry a lifecycle policy: keep an output intact while it is recent, reduce it
177
+ to a stub later, and remove it from model context when it is stale.
178
+ `NO_MESSAGE` keeps operational chatter out of model context immediately. These
179
+ policies affect only what the model sees; runtime events and persisted messages
180
+ retain the full record.
181
+
182
+ The prompt is not assembled behind an opaque stack of framework layers. The
183
+ complete generated system prompt is available before invocation:
184
+
185
+ ```python
186
+ print(agent.full_system_prompt)
187
+ ```
188
+
189
+ ## One execution abstraction
190
+
191
+ Roboz uses tools for work and for orchestration instead of adding a separate
192
+ hook mechanism for each new concern.
193
+
194
+ | Concern | Roboz abstraction |
195
+ | --- | --- |
196
+ | A model-selectable action | Active `@tool` |
197
+ | A deterministic follow-up | Passive chained tool |
198
+ | Runtime configuration or dependencies | `@factory` bound to a concrete typed object |
199
+ | Startup, preflight, and default flow | `default_tools` |
200
+ | Synchronous delegation | A subagent exposed as a named tool |
201
+ | Background work | An idempotent background-start tool in the default flow |
202
+
203
+ Tools remain independently testable callables with typed inputs and outputs.
204
+ An agent's dependency view is derived from this same tool graph rather than a
205
+ second registry.
206
+
207
+ ## Put models where they belong
208
+
209
+ Each agent owns its endpoint. A model-backed factory can bind another endpoint
210
+ directly, so a planner, specialist, summarizer, or transcription tool does not
211
+ have to share a model merely because it belongs to the same workflow.
212
+ `LLMEndpointRoute` follows a typed endpoint getter when a tool or agent should
213
+ track live model selection; concrete endpoints keep other uses fixed.
214
+
215
+ Provider SDKs remain outside core. The `roboz` package supplies the agent,
216
+ tooling, model, runtime, persistence, dependency, and deployment primitives;
217
+ install integrations only where they are needed.
218
+
219
+ ## Core primitives
220
+
221
+ | Primitive | Role |
222
+ | --- | --- |
223
+ | `roboz.Agent` | Owns the active tool surface, prompt, invoke loop, and runtime events. |
224
+ | `roboz.tool` | Defines an action with typed input and output models. |
225
+ | `roboz.factory` | Binds a concrete typed context or resource to a tool. |
226
+ | `roboz.Skill` | Packages reusable instructions and optional tools. |
227
+ | `roboz.models.Message` | Carries content and its model-context lifecycle. |
228
+ | `roboz.deployment.DeployableAgent` | Composes capabilities, subagents, and background agents. |
229
+
230
+ ## Optional ecosystem
231
+
232
+ Start with core and add only the integrations the application needs.
233
+
234
+ | Distribution | Adds |
235
+ | --- | --- |
236
+ | `roboshed` | Guarded file and CLI tools, memory, compaction, reusable agents, and deployment recipes. |
237
+ | `roboz-endpoints` | Lazy model catalogues and SDK adapters for OpenAI-compatible providers. |
238
+ | `roboz-proton-bridge` | Proton Bridge email tools. |
239
+
240
+ See the [add-on guide](docs/addons.md) for installation and composition, and the
241
+ [endpoint guide](packages/endpoints/README.md) for model selection and provider
242
+ adapters.
243
+
244
+ ## Documentation
245
+
246
+ | Guide | Start here for |
247
+ | --- | --- |
248
+ | [Tool authoring](docs/tool-authoring.md) | Chaining, factories, conditions, and typed handoffs |
249
+ | [Agent authoring](docs/agent-authoring.md) | Agent composition and prompt policy |
250
+ | [Reference](docs/reference.md) | Runtime and API semantics |
251
+ | [Message truncation example](examples/message_truncation.py) | Sliding model-context visibility |
252
+ | [Testing practices](docs/testing-practices.md) | Deterministic workflow and contract tests |
253
+
254
+ ## Development
255
+
256
+ ```bash
257
+ uv sync --locked --dev
258
+ uv run pytest
259
+ uv run ruff check
260
+ uv run pyright
261
+ bash scripts/run_type_tests.sh
262
+ ```
263
+
264
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the
265
+ [build and test guide](docs/build-and-test.md) for the complete release gate.
266
+ Roboz is typed and ships a PEP 561 `py.typed` marker.
267
+
268
+ ## License
269
+
270
+ Roboz is licensed under the [Apache License 2.0](LICENSE). Copyright © 2026 Tachion Oy.
@@ -0,0 +1,241 @@
1
+ <div align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/roboz-logo-dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="docs/assets/roboz-logo-light.svg">
5
+ <img alt="RoboZ" src="docs/assets/roboz-logo-dark.svg" width="560">
6
+ </picture>
7
+
8
+ <p><strong>Chain tools. Skip calls.</strong></p>
9
+ </div>
10
+
11
+ RoboZ is a framework for building llm powered agents. The core ingredient is that every tool can may be chained conditionally to a subsequent tool thus allowing easy injection of deterministic flows into agentic processes.
12
+
13
+ The package root contains the concise agent and tool authoring API. Models, LLM
14
+ operations, built-in tools, and runtime interfaces live in their corresponding
15
+ domain namespaces; see [public imports](docs/imports.md).
16
+
17
+ [![CI](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml/badge.svg)](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml)
18
+ [![Python 3.13+](https://img.shields.io/badge/Python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
19
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
20
+
21
+ > [!WARNING]
22
+ > RoboZ is pre-release software requiring Python 3.13 or newer. APIs may change
23
+ > before 1.0.
24
+
25
+ ## Basic idea
26
+
27
+ ![The usual agent loop sends every lunch-planning step back through the agent. A Roboz chain returns to the agent when Bob wants no lunch, passes any cuisine into one parameterized restaurant search, and retries the plan directly when no seats are available.](docs/assets/tool-chaining.svg)
28
+
29
+ ### Problems in agents: Context bloat and excessive back-and-forth
30
+ Suppose the task we want to achieve is ask our buddy Bob out to lunch and then book a table. For the sake of argument assume that our agent has access to the following MCP servers (Note: this is an example, RoboZ has native Tool primitives):
31
+
32
+ - Ask Bob what they want
33
+ - Find a restaurant
34
+ - Book a table.
35
+
36
+ In the usual approach an agent is presented each MCP server separately in the their system prompt and it must call them one-by-one to complete the task. When the agent is completing the task, at every turn it must choose the correct tool, formulate its output accordingly and absorb the reply into its context, which already must contain the specific instructions on how to use each tool. In addition, at each turn one has to wait for the llm to reply, each reply costs tokens and each reply risks a mistake from the llm.
37
+
38
+ ### Deterministic chains
39
+ The philosophy in RoboZ is that the workflow is deterministic an only choosing when to initiate is the agent's job. In RoboZ the agent would trigger the "ask Bob what they want" tool and all subsequent steps come by chaining: each tool is chained to other tools upstream and their output is passed down to the chained tool. Each link/edge may introduce a True/False condition, in this case for example if Bob interested in having lunch (with us). If he is not, RoboZ allows for the chain to break and returns back to the default tool, which for an agentic process is usually "ask the llm what to do next". The default mode is that chained tools are not presented to the agent, they are thus *passive* or in other words their role is strictly in forming deterministic workflows and they cannot be invoked.
40
+
41
+ ### Message truncation
42
+ Lengthy tasks with many tool calls also add many tokens in the context that may not be relevant to the end result. In RoboZ all tools may choose to truncate their message i.e. not show it to the agent in its complete form or only show it in its entirety a few times and then remove it from the agents context entirely, for example.
43
+
44
+
45
+
46
+
47
+
48
+ ## Code example
49
+ TBD
50
+
51
+
52
+ ```python
53
+ from roboz import tool
54
+ from roboz.models import Empty, Message
55
+
56
+
57
+ class LunchPreference(Empty):
58
+ cuisine: str | None
59
+
60
+
61
+ class Restaurant(Empty):
62
+ name: str
63
+ seats_available: bool
64
+
65
+
66
+ class Booking(Empty):
67
+ confirmation: str
68
+
69
+
70
+ @tool
71
+ def plan_lunch_with_bob(
72
+ input: Empty, messages: list[Message]
73
+ ) -> LunchPreference:
74
+ ...
75
+
76
+
77
+ @tool
78
+ def retry_plan_lunch_with_bob(
79
+ input: Restaurant, messages: list[Message]
80
+ ) -> LunchPreference:
81
+ ...
82
+
83
+
84
+ @tool(
85
+ chained_to=[plan_lunch_with_bob, retry_plan_lunch_with_bob],
86
+ chain_condition=lambda output: (
87
+ isinstance(output, LunchPreference)
88
+ and output.cuisine is not None
89
+ ),
90
+ )
91
+ def find_restaurant(
92
+ input: LunchPreference, messages: list[Message]
93
+ ) -> Restaurant:
94
+ ...
95
+
96
+
97
+ retry_plan_lunch_with_bob.chain(
98
+ chained_to=find_restaurant,
99
+ chain_condition=lambda output: (
100
+ isinstance(output, Restaurant) and not output.seats_available
101
+ ),
102
+ )
103
+
104
+
105
+ @tool(
106
+ chained_to=find_restaurant,
107
+ chain_condition=lambda output: (
108
+ isinstance(output, Restaurant) and output.seats_available
109
+ ),
110
+ )
111
+ def book_a_table(input: Restaurant, messages: list[Message]) -> Booking:
112
+ ...
113
+ ```
114
+
115
+ ## factory closure, endpoint instance and seeing the entire prompt
116
+ TBD
117
+
118
+
119
+ ## Try it
120
+
121
+ ```bash
122
+ uv add roboz
123
+ ```
124
+
125
+ Or with pip:
126
+
127
+ ```bash
128
+ python -m pip install roboz
129
+ ```
130
+
131
+ The complete [quick start](examples/quickstart.py) uses a deterministic mock
132
+ endpoint. Bob first chooses sushi; when no seats are available, the typed chain
133
+ retries the planner, routes his second choice to pizza, and books—all from one
134
+ model-selected entry into the chain and without credentials:
135
+
136
+ ```bash
137
+ uv run python examples/quickstart.py
138
+ ```
139
+
140
+ For an unpublished checkout, first run `uv sync --locked --dev`. PyPI commands
141
+ require a published release; see the [build and test guide](docs/build-and-test.md)
142
+ for local wheels.
143
+
144
+ ## Control what reaches the model
145
+
146
+ Context is a projection, not an ever-growing transcript. Every `Message` can
147
+ carry a lifecycle policy: keep an output intact while it is recent, reduce it
148
+ to a stub later, and remove it from model context when it is stale.
149
+ `NO_MESSAGE` keeps operational chatter out of model context immediately. These
150
+ policies affect only what the model sees; runtime events and persisted messages
151
+ retain the full record.
152
+
153
+ The prompt is not assembled behind an opaque stack of framework layers. The
154
+ complete generated system prompt is available before invocation:
155
+
156
+ ```python
157
+ print(agent.full_system_prompt)
158
+ ```
159
+
160
+ ## One execution abstraction
161
+
162
+ Roboz uses tools for work and for orchestration instead of adding a separate
163
+ hook mechanism for each new concern.
164
+
165
+ | Concern | Roboz abstraction |
166
+ | --- | --- |
167
+ | A model-selectable action | Active `@tool` |
168
+ | A deterministic follow-up | Passive chained tool |
169
+ | Runtime configuration or dependencies | `@factory` bound to a concrete typed object |
170
+ | Startup, preflight, and default flow | `default_tools` |
171
+ | Synchronous delegation | A subagent exposed as a named tool |
172
+ | Background work | An idempotent background-start tool in the default flow |
173
+
174
+ Tools remain independently testable callables with typed inputs and outputs.
175
+ An agent's dependency view is derived from this same tool graph rather than a
176
+ second registry.
177
+
178
+ ## Put models where they belong
179
+
180
+ Each agent owns its endpoint. A model-backed factory can bind another endpoint
181
+ directly, so a planner, specialist, summarizer, or transcription tool does not
182
+ have to share a model merely because it belongs to the same workflow.
183
+ `LLMEndpointRoute` follows a typed endpoint getter when a tool or agent should
184
+ track live model selection; concrete endpoints keep other uses fixed.
185
+
186
+ Provider SDKs remain outside core. The `roboz` package supplies the agent,
187
+ tooling, model, runtime, persistence, dependency, and deployment primitives;
188
+ install integrations only where they are needed.
189
+
190
+ ## Core primitives
191
+
192
+ | Primitive | Role |
193
+ | --- | --- |
194
+ | `roboz.Agent` | Owns the active tool surface, prompt, invoke loop, and runtime events. |
195
+ | `roboz.tool` | Defines an action with typed input and output models. |
196
+ | `roboz.factory` | Binds a concrete typed context or resource to a tool. |
197
+ | `roboz.Skill` | Packages reusable instructions and optional tools. |
198
+ | `roboz.models.Message` | Carries content and its model-context lifecycle. |
199
+ | `roboz.deployment.DeployableAgent` | Composes capabilities, subagents, and background agents. |
200
+
201
+ ## Optional ecosystem
202
+
203
+ Start with core and add only the integrations the application needs.
204
+
205
+ | Distribution | Adds |
206
+ | --- | --- |
207
+ | `roboshed` | Guarded file and CLI tools, memory, compaction, reusable agents, and deployment recipes. |
208
+ | `roboz-endpoints` | Lazy model catalogues and SDK adapters for OpenAI-compatible providers. |
209
+ | `roboz-proton-bridge` | Proton Bridge email tools. |
210
+
211
+ See the [add-on guide](docs/addons.md) for installation and composition, and the
212
+ [endpoint guide](packages/endpoints/README.md) for model selection and provider
213
+ adapters.
214
+
215
+ ## Documentation
216
+
217
+ | Guide | Start here for |
218
+ | --- | --- |
219
+ | [Tool authoring](docs/tool-authoring.md) | Chaining, factories, conditions, and typed handoffs |
220
+ | [Agent authoring](docs/agent-authoring.md) | Agent composition and prompt policy |
221
+ | [Reference](docs/reference.md) | Runtime and API semantics |
222
+ | [Message truncation example](examples/message_truncation.py) | Sliding model-context visibility |
223
+ | [Testing practices](docs/testing-practices.md) | Deterministic workflow and contract tests |
224
+
225
+ ## Development
226
+
227
+ ```bash
228
+ uv sync --locked --dev
229
+ uv run pytest
230
+ uv run ruff check
231
+ uv run pyright
232
+ bash scripts/run_type_tests.sh
233
+ ```
234
+
235
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the
236
+ [build and test guide](docs/build-and-test.md) for the complete release gate.
237
+ Roboz is typed and ships a PEP 561 `py.typed` marker.
238
+
239
+ ## License
240
+
241
+ Roboz is licensed under the [Apache License 2.0](LICENSE). Copyright © 2026 Tachion Oy.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "roboz"
3
- version = "0.1.2.dev4"
3
+ version = "0.1.2.dev6"
4
4
  description = "Typed primitives for composable agentic workflows"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Tachion Oy" }]
@@ -0,0 +1,48 @@
1
+ """Lazy domain namespaces and concise authoring primitives for Roboz."""
2
+
3
+ from importlib import import_module
4
+ from typing import Final
5
+
6
+ _DOMAINS: Final = frozenset(
7
+ {
8
+ "agent",
9
+ "dependencies",
10
+ "deployment",
11
+ "exceptions",
12
+ "llm",
13
+ "models",
14
+ "runtime",
15
+ "skill",
16
+ "tooling",
17
+ "tools",
18
+ }
19
+ )
20
+ _AUTHORING_EXPORTS: Final = {
21
+ "Agent": ("roboz.agent", "Agent"),
22
+ "Factory": ("roboz.tooling", "Factory"),
23
+ "Skill": ("roboz.skill", "Skill"),
24
+ "Tool": ("roboz.tooling", "Tool"),
25
+ "factory": ("roboz.tooling", "factory"),
26
+ "tool": ("roboz.tooling", "tool"),
27
+ }
28
+
29
+ __all__ = list(_AUTHORING_EXPORTS) + sorted(_DOMAINS) # pyright: ignore[reportUnsupportedDunderAll]
30
+
31
+
32
+ def __getattr__(name: str) -> object:
33
+ """Load a declared public namespace or authoring primitive on first access."""
34
+ if name in _DOMAINS:
35
+ value = import_module(f"{__name__}.{name}")
36
+ else:
37
+ try:
38
+ module_name, attribute = _AUTHORING_EXPORTS[name]
39
+ except KeyError:
40
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
41
+ value = getattr(import_module(module_name), attribute)
42
+ globals()[name] = value
43
+ return value
44
+
45
+
46
+ def __dir__() -> list[str]:
47
+ """Return loaded globals together with every declared lazy export."""
48
+ return sorted(set(globals()) | set(__all__))
@@ -0,0 +1,20 @@
1
+ """Typed public namespaces and concise authoring primitives for Roboz."""
2
+
3
+ from roboz import agent as agent
4
+ from roboz import dependencies as dependencies
5
+ from roboz import deployment as deployment
6
+ from roboz import exceptions as exceptions
7
+ from roboz import llm as llm
8
+ from roboz import models as models
9
+ from roboz import runtime as runtime
10
+ from roboz import skill as skill
11
+ from roboz import tooling as tooling
12
+ from roboz import tools as tools
13
+ from roboz.agent import Agent as Agent
14
+ from roboz.skill import Skill as Skill
15
+ from roboz.tooling import Factory as Factory
16
+ from roboz.tooling import Tool as Tool
17
+ from roboz.tooling import factory as factory
18
+ from roboz.tooling import tool as tool
19
+
20
+ __all__: list[str]