roboz 0.1.2.dev7__tar.gz → 0.1.2.dev8__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 (68) hide show
  1. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/CHANGELOG.md +26 -15
  2. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/PKG-INFO +39 -43
  3. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/README.md +37 -41
  4. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/pyproject.toml +2 -2
  5. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/core.py +53 -35
  6. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/.gitignore +0 -0
  7. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/LICENSE +0 -0
  8. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/__init__.py +0 -0
  9. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/__init__.pyi +0 -0
  10. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/_naming.py +0 -0
  11. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/__init__.py +0 -0
  12. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/_execution_context.py +0 -0
  13. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/_identifiers.py +0 -0
  14. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/_notifications.py +0 -0
  15. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/_prompts.py +0 -0
  16. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/_tool_observer.py +0 -0
  17. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/background_agent.py +0 -0
  18. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/prompt_agent_tool.py +0 -0
  19. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/agent/subagent.py +0 -0
  20. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/dependencies.py +0 -0
  21. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/deployment.py +0 -0
  22. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/exceptions.py +0 -0
  23. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/__init__.py +0 -0
  24. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/_diagnostics.py +0 -0
  25. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/_retry.py +0 -0
  26. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/_truncation.py +0 -0
  27. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/binding.py +0 -0
  28. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/calls.py +0 -0
  29. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/completion.py +0 -0
  30. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/endpoints.py +0 -0
  31. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/openai_compatible.py +0 -0
  32. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/openrouter.py +0 -0
  33. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/llm/prompts.py +0 -0
  34. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/__init__.py +0 -0
  35. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/_schema.py +0 -0
  36. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/_serialization.py +0 -0
  37. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/_telemetry.py +0 -0
  38. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/core.py +0 -0
  39. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/messages.py +0 -0
  40. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/models/truncation.py +0 -0
  41. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/py.typed +0 -0
  42. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/__init__.py +0 -0
  43. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/_environment.py +0 -0
  44. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/_external.py +0 -0
  45. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/_logging.py +0 -0
  46. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/_paths.py +0 -0
  47. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/events.py +0 -0
  48. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/io.py +0 -0
  49. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/observability.py +0 -0
  50. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/persistence/__init__.py +0 -0
  51. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/persistence/activity.py +0 -0
  52. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/persistence/schema.py +0 -0
  53. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/pipe.py +0 -0
  54. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/runtime/sinks.py +0 -0
  55. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/skill/__init__.py +0 -0
  56. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/skill/_prompts.py +0 -0
  57. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/skill/core.py +0 -0
  58. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/__init__.py +0 -0
  59. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/_prompts.py +0 -0
  60. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/_protocols.py +0 -0
  61. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/_typing.py +0 -0
  62. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/context.py +0 -0
  63. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/core.py +0 -0
  64. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tooling/decorators.py +0 -0
  65. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tools/__init__.py +0 -0
  66. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tools/_identifiers.py +0 -0
  67. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tools/control.py +0 -0
  68. {roboz-0.1.2.dev7 → roboz-0.1.2.dev8}/src/roboz/tools/interaction.py +0 -0
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.2.dev8 - 2026-09-20
6
+
7
+ - Breaking: remove the legacy agent master tool. Model-driven agents run
8
+ their configured default tools followed by the built-in `prompt_agent` tool;
9
+ deterministic agents require and run only their configured default tools.
10
+ Use `default_tools` to configure deterministic steps instead of relying on
11
+ the removed `master_tool` attribute.
12
+
13
+ - Show every displayed tool's external dependency IDs and kinds in
14
+ `Agent.show_agent_info()`.
15
+
5
16
  ## 0.1.2.dev7 - 2026-09-20
6
17
 
7
18
  - Breaking: replace the `is_agentic` boolean with the string-valued
@@ -28,7 +39,7 @@
28
39
  verbatim instead of attempting action validation. Supply `LlmOutputModel=...`
29
40
  or `active_tools=...` to retain structured dictionary results and repair retries.
30
41
  Endpoint and callback arguments are mutually exclusive. See the
31
- [completion guide](docs/tool-authoring.md#standalone-llm-backed-tools).
42
+ [completion guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/tool-authoring.md#standalone-llm-backed-tools).
32
43
 
33
44
  ## 0.1.2.dev6 - 2026-09-15
34
45
 
@@ -36,7 +47,7 @@
36
47
  `Agent`, `Skill`, `Tool`, `Factory`, `tool`, and `factory` alongside discoverable
37
48
  domain namespaces. Import models from `roboz.models`, agent helpers from
38
49
  `roboz.agent`, built-in tools from `roboz.tools`, and context protocols from
39
- `roboz.tooling`. See [the import migration guide](docs/imports.md).
50
+ `roboz.tooling`. See [the import migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/imports.md).
40
51
 
41
52
  ## 0.1.2.dev5 - 2026-09-13
42
53
 
@@ -56,7 +67,7 @@
56
67
  stay side-effect free. Endpoints support explicit early `materialize()` calls
57
68
  while preserving their identity; prompt contexts delegate initialization.
58
69
  Breaking: OpenAI-compatible client protocols now require `close() -> None` for
59
- typed cleanup. See [the lifecycle contract](docs/dependency-primitives.md).
70
+ typed cleanup. See [the lifecycle contract](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md).
60
71
 
61
72
  - Make resource-inspection declarations explicit: aggregate contexts and agents
62
73
  implement the `HasExternalDependencies` protocol, renamed from `Context` with
@@ -72,20 +83,20 @@
72
83
  share supplied state. Agent inspection uses live tool methods, and deployment
73
84
  builders use the same bindings. Restore top-level agent, skill, and built-in
74
85
  tool exports; removed dependency and `Ctx` APIs stay removed. See
75
- [the primitive migration](docs/dependency-primitives.md).
86
+ [the primitive migration](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md).
76
87
 
77
88
  - Breaking: core endpoints require synchronous OpenAI-compatible clients instead
78
89
  of an untyped client. Client methods and request controls are checked statically;
79
90
  the real `openai.OpenAI` client satisfies the protocols without a wrapper or an
80
91
  SDK dependency in core. Replace placeholder or incompatible clients with a
81
- conforming chat/transcription client. See [the client contract](docs/dependency-primitives.md).
92
+ conforming chat/transcription client. See [the client contract](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md).
82
93
 
83
94
  - Breaking: external resource implementations must provide `check() -> bool` for
84
95
  explicit availability checks. Executables check PATH; core endpoints use model
85
96
  discovery without generating output. Results are uncached, absent resources
86
97
  return `False`, and check errors propagate. Binding, copying, and inspection
87
98
  never invoke checks. Plain contexts need no check method. See
88
- [resource inspection and availability](docs/dependency-primitives.md).
99
+ [resource inspection and availability](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md).
89
100
 
90
101
  - Accept any concretely typed factory context, including plain objects and lists.
91
102
  Contexts without resource inspection are passed through unchanged and their
@@ -95,7 +106,7 @@
95
106
  retaining their identity and client for execution and inspection. Endpoint
96
107
  request helpers and the selector now use concrete endpoints; lazy construction
97
108
  and companion migrations remain deferred. Scripted endpoints report no external
98
- resources. See [typed contexts and resource inspection](docs/dependency-primitives.md).
109
+ resources. See [typed contexts and resource inspection](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md).
99
110
  - Fix `@factory()` input inference so parenthesized factories retain the same
100
111
  concrete input, output, and context types as bare `@factory` declarations.
101
112
 
@@ -106,7 +117,7 @@
106
117
  stay in `roboz.dependencies`; the top-level API now exposes only data and
107
118
  tool/factory/context primitives. Remove legacy dependency bases, lazy/reference
108
119
  helpers, and checker registration. Agent, built-in tool, and companion consumers
109
- remain unmigrated; this checkpoint is not release-ready. See [typed contexts and resource inspection](docs/dependency-primitives.md)
120
+ remain unmigrated; this checkpoint is not release-ready. See [typed contexts and resource inspection](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/dependency-primitives.md)
110
121
  for the contract, removed APIs, and migration boundary.
111
122
 
112
123
  ## 0.1.2.dev4 - 2026-09-12
@@ -134,7 +145,7 @@
134
145
  and background agents start through default tools. Construct generic
135
146
  definitions directly with `DeployableAgent(...)`.
136
147
  Sandbox-aware `Deployment` lives in `roboshed.deployments`, not core.
137
- See `docs/agent-factories.md` for migration.
148
+ See [the archived agent migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/agent-factories.md) for migration.
138
149
 
139
150
  ## 0.1.2.dev2 - 2026-09-09
140
151
 
@@ -144,7 +155,7 @@
144
155
 
145
156
  - Breaking: move dependency primitives from `roboz.tooling.dependencies` and
146
157
  `roboz.tooling` to `roboz.dependencies`. Update those imports; the existing
147
- top-level `roboz` authoring API remains available. See `docs/context-migration.md`.
158
+ top-level `roboz` authoring API remains available. See [the archived context migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/context-migration.md).
148
159
 
149
160
  - Add `DependencyRoute` for live caller-owned selections. Materialization and discovery delegate to the current target without introducing a separate identity or caching the selection.
150
161
 
@@ -152,11 +163,11 @@
152
163
  Capabilities own their tool-specific endpoint choices and receive the agent
153
164
  endpoint as a fallback, independently of runtime controls. Lazy/live
154
165
  references retain identity and deferred resolution. See
155
- `docs/agent-factories.md` for builder migration.
166
+ [the archived agent migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/agent-factories.md) for builder migration.
156
167
 
157
- - Breaking: move the Librarian and its memory/summarization tools out of core into `roboshed.agents` and `roboshed.tools`. Use `librarian(sandbox, agent_names, agent_endpoint=...)` instead of `LibrarianConstructor` and its path record; see `docs/agent-factories.md`. Core retains control, interaction, and generic construction primitives.
168
+ - Breaking: move the Librarian and its memory/summarization tools out of core into `roboshed.agents` and `roboshed.tools`. Use `librarian(sandbox, agent_names, agent_endpoint=...)` instead of `LibrarianConstructor` and its path record; see [the archived agent migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/agent-factories.md). Core retains control, interaction, and generic construction primitives.
158
169
 
159
- - Add generic `AgentDefinition`, `AgentCapability`, `Capability`, and `SubAgentSpec` in `roboz.deployment`. Configure all tools and skills through capabilities, with fresh agent pipes and explicit sink configuration; definitions select no project, memory, or persistence conventions. See `docs/agent-factories.md`.
170
+ - Add generic `AgentDefinition`, `AgentCapability`, `Capability`, and `SubAgentSpec` in `roboz.deployment`. Configure all tools and skills through capabilities, with fresh agent pipes and explicit sink configuration; definitions select no project, memory, or persistence conventions. See [the archived agent migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/agent-factories.md).
160
171
 
161
172
  - Breaking: `roboz[shed]` now installs `roboshed` instead of `roboz-shed`. Update direct requirements to `roboshed` and imports from `roboz_shed` to `roboshed`; no compatibility package is provided.
162
173
 
@@ -177,7 +188,7 @@
177
188
  Contexts implement `ExternalDependencySource`, preserving resource identity
178
189
  and reflecting live nested contexts, agents, and catalogs without resolving
179
190
  lazy resources. `external_dependencies` is now a reserved context field name;
180
- see `docs/context-migration.md`.
191
+ see [the archived context migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/context-migration.md).
181
192
 
182
193
  ### Fixed
183
194
 
@@ -189,7 +200,7 @@
189
200
  - **Breaking:** Construct tool contexts with `Ctx(**values)` and pass resources
190
201
  directly. Remove `FactoryCtx`, specialized context classes, `ToolDependency`,
191
202
  and endpoint binding wrappers; `Tool.dependencies` now returns resources.
192
- See `docs/context-migration.md` for replacements and state ownership.
203
+ See [the archived context migration guide](https://github.com/Tachion-Oy/roboz/blob/roboz-v0.1.2.dev7/docs/context-migration.md) for replacements and state ownership.
193
204
 
194
205
  - Define and enforce Google-style source docstrings, and normalize tool
195
206
  docstrings before including them in agent prompts.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: roboz
3
- Version: 0.1.2.dev7
3
+ Version: 0.1.2.dev8
4
4
  Import-Name: roboz
5
5
  Summary: Typed primitives for composable agentic workflows
6
6
  Project-URL: Homepage, https://github.com/Tachion-Oy/roboz
7
7
  Project-URL: Repository, https://github.com/Tachion-Oy/roboz
8
8
  Project-URL: Issues, https://github.com/Tachion-Oy/roboz/issues
9
- Project-URL: Documentation, https://github.com/Tachion-Oy/roboz/tree/main/docs
9
+ Project-URL: Documentation, https://github.com/Tachion-Oy/roboz#readme
10
10
  Author: Tachion Oy
11
11
  License-Expression: Apache-2.0
12
12
  License-File: LICENSE
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
37
37
  <p><strong>Chain tools. Skip calls.</strong></p>
38
38
  </div>
39
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.
40
+ RoboZ is a framework for building llm powered agents. The core ingredient is that every tool may be chained conditionally to a subsequent tool thus allowing easy injection of deterministic flows into agentic processes.
41
41
 
42
42
  [![CI](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml/badge.svg)](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml)
43
43
  [![Python 3.13+](https://img.shields.io/badge/Python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
@@ -58,10 +58,10 @@ Suppose the task we want to achieve is ask our buddy Bob out to lunch and then b
58
58
  - Find a restaurant
59
59
  - Book a table.
60
60
 
61
- 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.
61
+ In the usual approach an agent is presented each MCP server separately in 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.
62
62
 
63
63
  ### Deterministic chains
64
- The philosophy in RoboZ is that of a a workflow is (mostly) deterministic an only on occasion does one need to call an llm. For example in RoboZ an agent would trigger the "ask Bob if they wan to have lunch" tool and all subsequent steps come by chaining: each tool can be chained to other tools upstream where their outputs are passed down the chain. Each link/edge may introduce a True/False condition, in our 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.
64
+ The philosophy in RoboZ is that a workflow is (mostly) deterministic and only on occasion does one need to call an llm. For example in RoboZ an agent would trigger the "ask Bob if they want to have lunch" tool and all subsequent steps come by chaining: each tool can be chained to other tools upstream where their outputs are passed down the chain. Each link/edge may introduce a True/False condition, in our case for example if Bob is 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.
65
65
 
66
66
  Chaining not only reduces the llm calls, but it also provides a useful way of introducing a fine-grained guard layer for tool calls. This is in fact precisely how the cli tools and their access policies work in Roboz. For a cli command a chained passive tool evaluates the intent and breaks the chain if policies are violated.
67
67
 
@@ -99,19 +99,21 @@ output, messages_ = agent.invoke()
99
99
  print(f'"{output.value}"')
100
100
  ```
101
101
 
102
- The above [simple example](examples/simple.py) can be run from the root with
102
+ The above [simple example](examples/simple.py) uses the accompanying
103
+ [quote file](examples/simpsons_quotes.py) in this repository. Run it from the
104
+ repository root with
103
105
 
104
- ```python
106
+ ```bash
105
107
  uv run python examples/simple.py
106
108
  ```
107
109
  It creates an agent that returns a random
108
- Simpsons quote. It uses a mock endpoint, with pre-determined replies, so you can run it without API keys.
110
+ Simpsons quote. **The docstring in the tool is the instruction that the agent sees**. It uses a mock endpoint, with pre-determined replies, so you can run it without API keys.
109
111
  The main contracts of RoboZ are already visible:
110
112
 
111
113
  - `@tool` creates an instance of a usable tool for the agent
112
114
  - A tool's input and output are typed. Tools also receive the entire message stack
113
- - Callable endpoints are single instances, as a hard rule
114
- - Different output types impact the dymanics, importantly `Stop` breaks out of the agentic loop
115
+ - Callable endpoints are single instances, as a hard rule
116
+ - Different output types impact the dynamics, importantly `Stop` breaks out of the agentic loop
115
117
  - `agent.invoke()` runs the agent and returns its output `Stop` and messages.
116
118
 
117
119
  The above does not show the main idea of tool chaining, for that read the following sections.
@@ -119,7 +121,7 @@ The above does not show the main idea of tool chaining, for that read the follow
119
121
 
120
122
  An agent is a loop that calls tools. Everything is defined as a tool: Skills, background agents, prompting the agent, prompting the user, running nested agents, start up hooks etc. Everything.
121
123
 
122
- **A tool can be trigger in three ways:**
124
+ **A tool can be triggered in three ways:**
123
125
  - **Invoked by an agent**: The `prompt_agent` tool asks an LLM what to do next and its `Invoke` output always calls another tool. It is constructed internally for `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` agents, but it is still just a tool.
124
126
  - **By chaining**. After an invoked tool has fired RoboZ checks if a chained tool with a *true* chain condition exists (for more than one *true* condition for a fork you get a runtime error). If yes, the output is passed on and the process repeats until the first broken chain or all chained tools are exhausted
125
127
  - **As default tools**. Once the tool chain is exhausted or the chain breaks due to a *false* condition the loop returns to the freely defined `default_tool` (there actually can be many, they are all called in sequence).
@@ -130,13 +132,13 @@ RoboZ then collapses to the traditional agentic approach as a special case if on
130
132
  ### Tool Chaining
131
133
  This may be used to reduce the number of llm calls, leading to a speed increase, lower cost and fewer AI errors. It also provides a useful way of introducing a guard layer for tool calls, which can be used to restrict agentic actions.
132
134
  ### Output Truncation
133
- A Tools output can be hidden from the llm, also partially, and this can start to apply after the message has been shown N times.
135
+ A tool’s output can be hidden from the llm, also partially, and this can start to apply after the message has been shown N times.
134
136
  ### Tool outputs are typed
135
- The contract in RoboZ is that all tool calls and hence in everything that happens is that outputs are typed classes. Agents and tools never exchange raw strings or even JSON, typed classes and validation are present throughout, with designated classes for tasks such as `Invoke` and `Stop`.
136
- ### LLm Endpoints are instances
137
- As strict design rule in Roboz, everything that depends on an LLM call must be trivially swappable to another provider or model. This makes changing an agent endpoint trivial and furthermore multi-endpoint functionality, where inside a single agent several endpoints are implemented, quite easy.
137
+ The contract in RoboZ is that every action in the agentic loop is a tool call and all outputs are typed classes. Raw strings or JSON is never exchanged (unless explicitly opted in) as is and typed classes and validation are present throughout, with designated classes for tasks such as `Invoke` and `Stop`.
138
+ ### LLM Endpoints are instances
139
+ As a fundamental design rule in Roboz, everything that depends on an LLM call must be trivially swappable to another provider or model. This makes changing an agent endpoint trivial and furthermore multi-endpoint functionality, where inside a single agent several endpoints are implemented, quite easy.
138
140
 
139
- The [simple example](examples/simple.py) above does not fully illustrate how these features of RoboZ work. For that see [complex example](examples/complex.py) example below.
141
+ To see the above in practice see the [complex example](examples/complex.py) example below.
140
142
 
141
143
 
142
144
 
@@ -145,14 +147,15 @@ The [simple example](examples/simple.py) above does not fully illustrate how the
145
147
 
146
148
  In the code example below we illustrate some of the features that make RoboZ different from other frameworks.
147
149
 
148
- **Tool chaining** is usually introduced via the decorator argument `chained_to` which indicates the name of the tool whose output is passed as the input. The input/output contract must be Liskov compatible, i.e the upstream output must be a subclass of the downstream input. A possible chain condition can be passed in via the `chain_condition` callable, which uses by definition the tool's input argument and returns a boolean. The chain condition must evaluate to at most one true condition, but it can evaluate to `false` on all links, in which case you return to the default tool(s). `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` construct a `prompt_agent` tool backed by the agent endpoint; `AgentMode.DETERMINISTIC` uses the configured default tools.
150
+ **Tool chaining** is usually introduced via the decorator argument `chained_to` which indicates the name of the tool whose output is passed as the input (the tools also possess a `.chain` method). The input/output contract must be Liskov compatible, i.e the upstream output must be a subclass of the downstream input. A possible `chain_condition` can be passed in, which by definition has access to the tool's input argument and returns a boolean. The chain condition must evaluate to at most one true condition, but it can evaluate to `false` on all links, in which case you return to the default tool(s). `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` construct a `prompt_agent` tool backed by the agent endpoint; `AgentMode.DETERMINISTIC` uses the configured default tools.
149
151
 
150
152
  The `escalate` is an example of a **tool factory**, which is a simple concept. It accepts a context parameter which is added to the tool's closure and calling the factory with a context argument returns a tool. A very common use case is a tool with an endpoint as a context. In RoboZ all llm **endpoints are instances**, so it is easy to have a specific endpoint for a tool, that is different from that of the agent, below we construct deterministic mock endpoints so that no API keys are required for the examples. Factories have precisely the same chaining arguments in their decorator as a tool.
151
153
 
152
- Another useful feature demonstrated below in the `escalate` factory is **message truncation**. This parameter is present in all output types and allows the tool to decide if the output should be visible in the conversation passed on to the agent. It can truncate partially (show only n chars or just a caller stub) or completely. Importantly, we can choose to start applying the truncation only after the complete message has been shown to the agent n times. Below, we choose to show the message once and then truncate it completely, as useful pattern for example for long tracebacks etc.
154
+ Also demonstrated in the `escalate` factory is the **message truncation** feature. This parameter is present in all output types and allows the tool to decide if the output should be visible in the conversation passed on to the agent. A message can be truncated partially (show only n chars or just a caller stub) or completely. Importantly, we can choose to start applying the truncation only after the complete message has been shown to the agent n times. Below, we choose to show the message once and then truncate it completely, a useful pattern for example for long tracebacks etc.
153
155
 
154
- All RoboZ tools by definition include the full conversation **messages** as input. They are not intended to be altered in place (although they can be and this is how e.g. *compactification* works), but can be used to alter the behavior of tools in a non-trivial way. For example, a start up hook intended to show the agent some information at the start or performing some initial maintenance can simply be one of the default tools that checks if it has already been called and if it has, does nothing.
156
+ All RoboZ tools by definition include the full **conversation messages** as input. These are not intended to be altered in place (although they can be and this is how e.g. *conversation compactification* works), but can be used to alter the behavior of tools in a non-trivial way. For example, a start up hook intended to show the agent some information at the start or performing some initial maintenance can simply be one of the default tools that checks if it has already been called and if it has, does nothing.
155
157
 
158
+ **The tool instruction is its docstring**. In addition, the system prompt includes a *technical prompt* by default that gives the specific tool calling instructions. This can of course be switched off. When in doubt, you can always use the method `.show_agent_info()` to check the complete agent configuration including the system prompt, tools, dependencies, persistence locations etc.
156
159
 
157
160
 
158
161
 
@@ -227,12 +230,12 @@ agent.invoke()
227
230
 
228
231
  The above [complex example](examples/complex.py) can be run from the root with
229
232
 
230
- ```python
233
+ ```bash
231
234
  uv run python examples/complex.py
232
235
  ```
233
236
 
234
237
 
235
- ## Try it
238
+ ## Try it out
236
239
 
237
240
  ```bash
238
241
  uv add roboz
@@ -244,29 +247,21 @@ Or with pip:
244
247
  python -m pip install roboz
245
248
  ```
246
249
 
247
- ## Optional ecosystem
248
-
249
- Start with core and add only the integrations the application needs.
250
-
251
- | Distribution | Adds |
252
- | --- | --- |
253
- | `roboshed` | Guarded file and CLI tools, memory, compaction, reusable agents, and deployment recipes. |
254
- | `roboz-endpoints` | Lazy model catalogues and SDK adapters for OpenAI-compatible providers. |
255
- | `roboz-proton-bridge` | Proton Bridge email tools. |
250
+ ## Packages
256
251
 
257
- See the [add-on guide](docs/addons.md) for installation and composition, and the
258
- [endpoint guide](packages/endpoints/README.md) for model selection and provider
259
- adapters.
252
+ This repository contains four independently versioned Python distributions.
253
+ They share development and release tooling, but are published separately so an
254
+ application only needs to install the parts it uses.
260
255
 
261
- ## Documentation
256
+ | Distribution | Import | Provides |
257
+ | --- | --- | --- |
258
+ | `roboz` | `roboz` | Core agent, tool, workflow, endpoint, and runtime primitives. |
259
+ | [`roboshed`](packages/shed/README.md) | `roboshed` | Reusable capabilities, guarded system tools, memory, agents, and deployment building blocks. |
260
+ | [`roboz-endpoints`](packages/endpoints/README.md) | `roboz_endpoints` | Model catalogues and optional provider adapters. |
261
+ | [`roboz-proton-bridge`](packages/proton-bridge/README.md) | `roboz_proton_bridge` | Proton Bridge email integration. |
262
262
 
263
- | Guide | Start here for |
264
- | --- | --- |
265
- | [Tool authoring](docs/tool-authoring.md) | Chaining, factories, conditions, and typed handoffs |
266
- | [Agent authoring](docs/agent-authoring.md) | Agent composition and prompt policy |
267
- | [Reference](docs/reference.md) | Runtime and API semantics |
268
- | [Complex chaining and truncation example](examples/complex.py) | Conditional chains, factory endpoints, and message visibility |
269
- | [Testing practices](docs/testing-practices.md) | Deterministic workflow and contract tests |
263
+ The companion packages build on `roboz`; `roboz-proton-bridge` also uses
264
+ `roboshed`.
270
265
 
271
266
  ## Development
272
267
 
@@ -278,8 +273,9 @@ uv run pyright
278
273
  bash scripts/run_type_tests.sh
279
274
  ```
280
275
 
281
- See [CONTRIBUTING.md](CONTRIBUTING.md) and the
282
- [build and test guide](docs/build-and-test.md) for the complete release gate.
276
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development and testing guidance. The
277
+ [verification workflow](.github/workflows/verify.yml) defines the complete CI
278
+ gate.
283
279
  Roboz is typed and ships a PEP 561 `py.typed` marker.
284
280
 
285
281
  ## License
@@ -8,7 +8,7 @@
8
8
  <p><strong>Chain tools. Skip calls.</strong></p>
9
9
  </div>
10
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.
11
+ RoboZ is a framework for building llm powered agents. The core ingredient is that every tool may be chained conditionally to a subsequent tool thus allowing easy injection of deterministic flows into agentic processes.
12
12
 
13
13
  [![CI](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml/badge.svg)](https://github.com/Tachion-Oy/roboz/actions/workflows/ci.yml)
14
14
  [![Python 3.13+](https://img.shields.io/badge/Python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
@@ -29,10 +29,10 @@ Suppose the task we want to achieve is ask our buddy Bob out to lunch and then b
29
29
  - Find a restaurant
30
30
  - Book a table.
31
31
 
32
- 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.
32
+ In the usual approach an agent is presented each MCP server separately in 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.
33
33
 
34
34
  ### Deterministic chains
35
- The philosophy in RoboZ is that of a a workflow is (mostly) deterministic an only on occasion does one need to call an llm. For example in RoboZ an agent would trigger the "ask Bob if they wan to have lunch" tool and all subsequent steps come by chaining: each tool can be chained to other tools upstream where their outputs are passed down the chain. Each link/edge may introduce a True/False condition, in our 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.
35
+ The philosophy in RoboZ is that a workflow is (mostly) deterministic and only on occasion does one need to call an llm. For example in RoboZ an agent would trigger the "ask Bob if they want to have lunch" tool and all subsequent steps come by chaining: each tool can be chained to other tools upstream where their outputs are passed down the chain. Each link/edge may introduce a True/False condition, in our case for example if Bob is 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.
36
36
 
37
37
  Chaining not only reduces the llm calls, but it also provides a useful way of introducing a fine-grained guard layer for tool calls. This is in fact precisely how the cli tools and their access policies work in Roboz. For a cli command a chained passive tool evaluates the intent and breaks the chain if policies are violated.
38
38
 
@@ -70,19 +70,21 @@ output, messages_ = agent.invoke()
70
70
  print(f'"{output.value}"')
71
71
  ```
72
72
 
73
- The above [simple example](examples/simple.py) can be run from the root with
73
+ The above [simple example](examples/simple.py) uses the accompanying
74
+ [quote file](examples/simpsons_quotes.py) in this repository. Run it from the
75
+ repository root with
74
76
 
75
- ```python
77
+ ```bash
76
78
  uv run python examples/simple.py
77
79
  ```
78
80
  It creates an agent that returns a random
79
- Simpsons quote. It uses a mock endpoint, with pre-determined replies, so you can run it without API keys.
81
+ Simpsons quote. **The docstring in the tool is the instruction that the agent sees**. It uses a mock endpoint, with pre-determined replies, so you can run it without API keys.
80
82
  The main contracts of RoboZ are already visible:
81
83
 
82
84
  - `@tool` creates an instance of a usable tool for the agent
83
85
  - A tool's input and output are typed. Tools also receive the entire message stack
84
- - Callable endpoints are single instances, as a hard rule
85
- - Different output types impact the dymanics, importantly `Stop` breaks out of the agentic loop
86
+ - Callable endpoints are single instances, as a hard rule
87
+ - Different output types impact the dynamics, importantly `Stop` breaks out of the agentic loop
86
88
  - `agent.invoke()` runs the agent and returns its output `Stop` and messages.
87
89
 
88
90
  The above does not show the main idea of tool chaining, for that read the following sections.
@@ -90,7 +92,7 @@ The above does not show the main idea of tool chaining, for that read the follow
90
92
 
91
93
  An agent is a loop that calls tools. Everything is defined as a tool: Skills, background agents, prompting the agent, prompting the user, running nested agents, start up hooks etc. Everything.
92
94
 
93
- **A tool can be trigger in three ways:**
95
+ **A tool can be triggered in three ways:**
94
96
  - **Invoked by an agent**: The `prompt_agent` tool asks an LLM what to do next and its `Invoke` output always calls another tool. It is constructed internally for `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` agents, but it is still just a tool.
95
97
  - **By chaining**. After an invoked tool has fired RoboZ checks if a chained tool with a *true* chain condition exists (for more than one *true* condition for a fork you get a runtime error). If yes, the output is passed on and the process repeats until the first broken chain or all chained tools are exhausted
96
98
  - **As default tools**. Once the tool chain is exhausted or the chain breaks due to a *false* condition the loop returns to the freely defined `default_tool` (there actually can be many, they are all called in sequence).
@@ -101,13 +103,13 @@ RoboZ then collapses to the traditional agentic approach as a special case if on
101
103
  ### Tool Chaining
102
104
  This may be used to reduce the number of llm calls, leading to a speed increase, lower cost and fewer AI errors. It also provides a useful way of introducing a guard layer for tool calls, which can be used to restrict agentic actions.
103
105
  ### Output Truncation
104
- A Tools output can be hidden from the llm, also partially, and this can start to apply after the message has been shown N times.
106
+ A tool’s output can be hidden from the llm, also partially, and this can start to apply after the message has been shown N times.
105
107
  ### Tool outputs are typed
106
- The contract in RoboZ is that all tool calls and hence in everything that happens is that outputs are typed classes. Agents and tools never exchange raw strings or even JSON, typed classes and validation are present throughout, with designated classes for tasks such as `Invoke` and `Stop`.
107
- ### LLm Endpoints are instances
108
- As strict design rule in Roboz, everything that depends on an LLM call must be trivially swappable to another provider or model. This makes changing an agent endpoint trivial and furthermore multi-endpoint functionality, where inside a single agent several endpoints are implemented, quite easy.
108
+ The contract in RoboZ is that every action in the agentic loop is a tool call and all outputs are typed classes. Raw strings or JSON is never exchanged (unless explicitly opted in) as is and typed classes and validation are present throughout, with designated classes for tasks such as `Invoke` and `Stop`.
109
+ ### LLM Endpoints are instances
110
+ As a fundamental design rule in Roboz, everything that depends on an LLM call must be trivially swappable to another provider or model. This makes changing an agent endpoint trivial and furthermore multi-endpoint functionality, where inside a single agent several endpoints are implemented, quite easy.
109
111
 
110
- The [simple example](examples/simple.py) above does not fully illustrate how these features of RoboZ work. For that see [complex example](examples/complex.py) example below.
112
+ To see the above in practice see the [complex example](examples/complex.py) example below.
111
113
 
112
114
 
113
115
 
@@ -116,14 +118,15 @@ The [simple example](examples/simple.py) above does not fully illustrate how the
116
118
 
117
119
  In the code example below we illustrate some of the features that make RoboZ different from other frameworks.
118
120
 
119
- **Tool chaining** is usually introduced via the decorator argument `chained_to` which indicates the name of the tool whose output is passed as the input. The input/output contract must be Liskov compatible, i.e the upstream output must be a subclass of the downstream input. A possible chain condition can be passed in via the `chain_condition` callable, which uses by definition the tool's input argument and returns a boolean. The chain condition must evaluate to at most one true condition, but it can evaluate to `false` on all links, in which case you return to the default tool(s). `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` construct a `prompt_agent` tool backed by the agent endpoint; `AgentMode.DETERMINISTIC` uses the configured default tools.
121
+ **Tool chaining** is usually introduced via the decorator argument `chained_to` which indicates the name of the tool whose output is passed as the input (the tools also possess a `.chain` method). The input/output contract must be Liskov compatible, i.e the upstream output must be a subclass of the downstream input. A possible `chain_condition` can be passed in, which by definition has access to the tool's input argument and returns a boolean. The chain condition must evaluate to at most one true condition, but it can evaluate to `false` on all links, in which case you return to the default tool(s). `AgentMode.STEERABLE` and `AgentMode.AUTONOMOUS` construct a `prompt_agent` tool backed by the agent endpoint; `AgentMode.DETERMINISTIC` uses the configured default tools.
120
122
 
121
123
  The `escalate` is an example of a **tool factory**, which is a simple concept. It accepts a context parameter which is added to the tool's closure and calling the factory with a context argument returns a tool. A very common use case is a tool with an endpoint as a context. In RoboZ all llm **endpoints are instances**, so it is easy to have a specific endpoint for a tool, that is different from that of the agent, below we construct deterministic mock endpoints so that no API keys are required for the examples. Factories have precisely the same chaining arguments in their decorator as a tool.
122
124
 
123
- Another useful feature demonstrated below in the `escalate` factory is **message truncation**. This parameter is present in all output types and allows the tool to decide if the output should be visible in the conversation passed on to the agent. It can truncate partially (show only n chars or just a caller stub) or completely. Importantly, we can choose to start applying the truncation only after the complete message has been shown to the agent n times. Below, we choose to show the message once and then truncate it completely, as useful pattern for example for long tracebacks etc.
125
+ Also demonstrated in the `escalate` factory is the **message truncation** feature. This parameter is present in all output types and allows the tool to decide if the output should be visible in the conversation passed on to the agent. A message can be truncated partially (show only n chars or just a caller stub) or completely. Importantly, we can choose to start applying the truncation only after the complete message has been shown to the agent n times. Below, we choose to show the message once and then truncate it completely, a useful pattern for example for long tracebacks etc.
124
126
 
125
- All RoboZ tools by definition include the full conversation **messages** as input. They are not intended to be altered in place (although they can be and this is how e.g. *compactification* works), but can be used to alter the behavior of tools in a non-trivial way. For example, a start up hook intended to show the agent some information at the start or performing some initial maintenance can simply be one of the default tools that checks if it has already been called and if it has, does nothing.
127
+ All RoboZ tools by definition include the full **conversation messages** as input. These are not intended to be altered in place (although they can be and this is how e.g. *conversation compactification* works), but can be used to alter the behavior of tools in a non-trivial way. For example, a start up hook intended to show the agent some information at the start or performing some initial maintenance can simply be one of the default tools that checks if it has already been called and if it has, does nothing.
126
128
 
129
+ **The tool instruction is its docstring**. In addition, the system prompt includes a *technical prompt* by default that gives the specific tool calling instructions. This can of course be switched off. When in doubt, you can always use the method `.show_agent_info()` to check the complete agent configuration including the system prompt, tools, dependencies, persistence locations etc.
127
130
 
128
131
 
129
132
 
@@ -198,12 +201,12 @@ agent.invoke()
198
201
 
199
202
  The above [complex example](examples/complex.py) can be run from the root with
200
203
 
201
- ```python
204
+ ```bash
202
205
  uv run python examples/complex.py
203
206
  ```
204
207
 
205
208
 
206
- ## Try it
209
+ ## Try it out
207
210
 
208
211
  ```bash
209
212
  uv add roboz
@@ -215,29 +218,21 @@ Or with pip:
215
218
  python -m pip install roboz
216
219
  ```
217
220
 
218
- ## Optional ecosystem
219
-
220
- Start with core and add only the integrations the application needs.
221
-
222
- | Distribution | Adds |
223
- | --- | --- |
224
- | `roboshed` | Guarded file and CLI tools, memory, compaction, reusable agents, and deployment recipes. |
225
- | `roboz-endpoints` | Lazy model catalogues and SDK adapters for OpenAI-compatible providers. |
226
- | `roboz-proton-bridge` | Proton Bridge email tools. |
221
+ ## Packages
227
222
 
228
- See the [add-on guide](docs/addons.md) for installation and composition, and the
229
- [endpoint guide](packages/endpoints/README.md) for model selection and provider
230
- adapters.
223
+ This repository contains four independently versioned Python distributions.
224
+ They share development and release tooling, but are published separately so an
225
+ application only needs to install the parts it uses.
231
226
 
232
- ## Documentation
227
+ | Distribution | Import | Provides |
228
+ | --- | --- | --- |
229
+ | `roboz` | `roboz` | Core agent, tool, workflow, endpoint, and runtime primitives. |
230
+ | [`roboshed`](packages/shed/README.md) | `roboshed` | Reusable capabilities, guarded system tools, memory, agents, and deployment building blocks. |
231
+ | [`roboz-endpoints`](packages/endpoints/README.md) | `roboz_endpoints` | Model catalogues and optional provider adapters. |
232
+ | [`roboz-proton-bridge`](packages/proton-bridge/README.md) | `roboz_proton_bridge` | Proton Bridge email integration. |
233
233
 
234
- | Guide | Start here for |
235
- | --- | --- |
236
- | [Tool authoring](docs/tool-authoring.md) | Chaining, factories, conditions, and typed handoffs |
237
- | [Agent authoring](docs/agent-authoring.md) | Agent composition and prompt policy |
238
- | [Reference](docs/reference.md) | Runtime and API semantics |
239
- | [Complex chaining and truncation example](examples/complex.py) | Conditional chains, factory endpoints, and message visibility |
240
- | [Testing practices](docs/testing-practices.md) | Deterministic workflow and contract tests |
234
+ The companion packages build on `roboz`; `roboz-proton-bridge` also uses
235
+ `roboshed`.
241
236
 
242
237
  ## Development
243
238
 
@@ -249,8 +244,9 @@ uv run pyright
249
244
  bash scripts/run_type_tests.sh
250
245
  ```
251
246
 
252
- See [CONTRIBUTING.md](CONTRIBUTING.md) and the
253
- [build and test guide](docs/build-and-test.md) for the complete release gate.
247
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development and testing guidance. The
248
+ [verification workflow](.github/workflows/verify.yml) defines the complete CI
249
+ gate.
254
250
  Roboz is typed and ships a PEP 561 `py.typed` marker.
255
251
 
256
252
  ## License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "roboz"
3
- version = "0.1.2.dev7"
3
+ version = "0.1.2.dev8"
4
4
  description = "Typed primitives for composable agentic workflows"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Tachion Oy" }]
@@ -51,7 +51,7 @@ include = ["/src/roboz", "/README.md", "/CHANGELOG.md", "/LICENSE", "/pyproject.
51
51
  Homepage = "https://github.com/Tachion-Oy/roboz"
52
52
  Repository = "https://github.com/Tachion-Oy/roboz"
53
53
  Issues = "https://github.com/Tachion-Oy/roboz/issues"
54
- Documentation = "https://github.com/Tachion-Oy/roboz/tree/main/docs"
54
+ Documentation = "https://github.com/Tachion-Oy/roboz#readme"
55
55
 
56
56
  [tool.pytest.ini_options]
57
57
  addopts = "--cov=roboz --cov-report=term-missing --ignore=tests/type_tests"
@@ -176,6 +176,8 @@ class Agent(HasExternalDependencies):
176
176
  "Model-driven flows require a non-empty system_prompt."
177
177
  )
178
178
  self.default_tools = [] if default_tools is None else list(default_tools)
179
+ if self.mode is AgentMode.DETERMINISTIC and not self.default_tools:
180
+ raise ValueError("No default tools for a deterministic instance.")
179
181
  if (
180
182
  not self.mode.allows_user_interaction
181
183
  and custom_prompt_user_tool is not None
@@ -261,22 +263,20 @@ class Agent(HasExternalDependencies):
261
263
  }
262
264
  return Agent(**(old_input | overrides))
263
265
 
264
- def _init_default_tool(self):
265
- if self.mode is not AgentMode.DETERMINISTIC:
266
- endpoint = self.agent_endpoint
267
- if endpoint is None:
268
- raise RuntimeError("model-driven instance has no endpoint")
269
- self.master_tool = prompt_agent(
270
- PromptAgentContext(
271
- active_tools=tuple(self.active_tools.values()),
272
- endpoint=endpoint,
273
- pipe=self.pipe,
274
- )
275
- )
266
+ def _init_prompt_agent_tool(self) -> None:
267
+ if self.mode is AgentMode.DETERMINISTIC:
268
+ self._prompt_agent_tool = None
276
269
  return
277
- if not self.default_tools:
278
- raise ValueError("No default tools for a deterministic instance.")
279
- self.master_tool = self.default_tools[0]
270
+ endpoint = self.agent_endpoint
271
+ if endpoint is None:
272
+ raise RuntimeError("model-driven instance has no endpoint")
273
+ self._prompt_agent_tool = prompt_agent(
274
+ PromptAgentContext(
275
+ active_tools=tuple(self.active_tools.values()),
276
+ endpoint=endpoint,
277
+ pipe=self.pipe,
278
+ )
279
+ )
280
280
 
281
281
  def _init_tools(self, *, tools: Sequence[Tool], skill: Skill | None):
282
282
  for t in self.default_tools:
@@ -295,8 +295,8 @@ class Agent(HasExternalDependencies):
295
295
  self.passive_tools[t.id] = t
296
296
  continue
297
297
  self.active_tools[t.id] = t
298
- self._init_default_tool()
299
- self._validate_tool_chains(all_tools | {self.master_tool})
298
+ self._init_prompt_agent_tool()
299
+ self._validate_tool_chains(all_tools)
300
300
 
301
301
  def external_dependencies(
302
302
  self,
@@ -305,7 +305,7 @@ class Agent(HasExternalDependencies):
305
305
  ) -> tuple[ExternalDependency, ...]:
306
306
  """Derive the agent's dependency catalog exclusively from its Tool graph."""
307
307
  tools: list[Tool | None] = [
308
- self.master_tool,
308
+ self._prompt_agent_tool,
309
309
  self.prompt_user_tool,
310
310
  *self.default_tools,
311
311
  *self.active_tools.values(),
@@ -417,8 +417,8 @@ class Agent(HasExternalDependencies):
417
417
  """Return the next default tool, starting a new scheduling cycle as needed."""
418
418
  if not self._ephemeral_default_tools:
419
419
  self._ephemeral_default_tools = list(self.default_tools)
420
- if self.mode is not AgentMode.DETERMINISTIC:
421
- self._ephemeral_default_tools.append(self.master_tool)
420
+ if self._prompt_agent_tool is not None:
421
+ self._ephemeral_default_tools.append(self._prompt_agent_tool)
422
422
  return self._ephemeral_default_tools.pop(0)
423
423
 
424
424
  def append_and_pipe(self, message: Message):
@@ -528,7 +528,7 @@ class Agent(HasExternalDependencies):
528
528
  }
529
529
  )
530
530
  self._init_skill(output)
531
- tool = self.get_next_tool(self.master_tool, output)
531
+ tool = self.get_next_tool(self._prompt_agent_tool, output)
532
532
  output = tool(output, self.messages)
533
533
  self.append_and_pipe(
534
534
  get_finalized_message(
@@ -719,6 +719,7 @@ class Agent(HasExternalDependencies):
719
719
  conf_table.add_column("Name", style="cyan")
720
720
  conf_table.add_column("Description")
721
721
  conf_table.add_column("Chained To")
722
+ conf_table.add_column("External Dependencies")
722
723
 
723
724
  no_description = "Not provided"
724
725
 
@@ -727,21 +728,36 @@ class Agent(HasExternalDependencies):
727
728
  return "-"
728
729
  return ", ".join([c.name for c in t.chained_to])
729
730
 
730
- conf_table.add_row(
731
- "Main Prompter",
732
- self.master_tool.name if self.master_tool.name else "Not set",
733
- f"Configured for {self.mode} execution.",
734
- "-",
735
- )
731
+ def _get_external_dependencies(tools: Sequence[Tool]) -> str:
732
+ dependencies = dedupe_external_dependencies(
733
+ dependency
734
+ for tool in tools
735
+ for dependency in tool.external_dependencies()
736
+ )
737
+ if not dependencies:
738
+ return "-"
739
+ return ", ".join(
740
+ f"{dependency.dependency_id} ({dependency.kind.value})"
741
+ for dependency in dependencies
742
+ )
736
743
 
737
- for id, t in self.active_tools.items():
738
- if id != self.master_tool.id:
739
- conf_table.add_row(
740
- "Active",
741
- t.name,
742
- t.description or no_description,
743
- _get_chained_to(t),
744
- )
744
+ if self._prompt_agent_tool is not None:
745
+ conf_table.add_row(
746
+ "Prompter",
747
+ self._prompt_agent_tool.name or "Not set",
748
+ f"Configured for {self.mode} execution.",
749
+ "-",
750
+ _get_external_dependencies((self._prompt_agent_tool,)),
751
+ )
752
+
753
+ for t in self.active_tools.values():
754
+ conf_table.add_row(
755
+ "Active",
756
+ t.name,
757
+ t.description or no_description,
758
+ _get_chained_to(t),
759
+ _get_external_dependencies((t,)),
760
+ )
745
761
 
746
762
  for id, t in self.passive_tools.items():
747
763
  conf_table.add_row(
@@ -749,6 +765,7 @@ class Agent(HasExternalDependencies):
749
765
  t.name,
750
766
  t.description or no_description,
751
767
  _get_chained_to(t),
768
+ _get_external_dependencies((t,)),
752
769
  )
753
770
 
754
771
  default_tool_names = (
@@ -761,6 +778,7 @@ class Agent(HasExternalDependencies):
761
778
  default_tool_names,
762
779
  "Configured fallback tool list.",
763
780
  "-",
781
+ _get_external_dependencies(self.default_tools),
764
782
  )
765
783
 
766
784
  console.print(conf_table, end="\n\n")
File without changes
File without changes