bub 0.5.0__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. bub-0.6.0/PKG-INFO +126 -0
  2. bub-0.6.0/README.md +70 -0
  3. {bub-0.5.0 → bub-0.6.0}/pyproject.toml +18 -15
  4. bub-0.6.0/src/bub/__init__.py +62 -0
  5. bub-0.6.0/src/bub/__main__.py +101 -0
  6. {bub-0.5.0 → bub-0.6.0}/src/bub/_version.py +2 -2
  7. bub-0.6.0/src/bub/application.py +35 -0
  8. bub-0.6.0/src/bub/builtin/__init__.py +6 -0
  9. bub-0.6.0/src/bub/builtin/agent.py +239 -0
  10. bub-0.6.0/src/bub/builtin/archive.py +85 -0
  11. bub-0.6.0/src/bub/builtin/auth.py +50 -0
  12. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/cli.py +37 -4
  13. bub-0.6.0/src/bub/builtin/codemode/__init__.py +103 -0
  14. bub-0.6.0/src/bub/builtin/commands.py +8 -0
  15. bub-0.6.0/src/bub/builtin/context.py +8 -0
  16. bub-0.6.0/src/bub/builtin/environment.py +25 -0
  17. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/hook_impl.py +96 -96
  18. bub-0.6.0/src/bub/builtin/model.py +180 -0
  19. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/onboarding.py +58 -85
  20. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/settings.py +85 -29
  21. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/shell_manager.py +7 -3
  22. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/spill.py +18 -51
  23. bub-0.6.0/src/bub/builtin/store.py +87 -0
  24. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/tools.py +132 -28
  25. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/cli/__init__.py +146 -44
  26. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/cli/renderer.py +5 -14
  27. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/cli/terminal_output.py +8 -6
  28. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/manager.py +104 -24
  29. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/message.py +0 -26
  30. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/telegram.py +1 -1
  31. {bub-0.5.0 → bub-0.6.0}/src/bub/configure.py +11 -0
  32. bub-0.6.0/src/bub/core/__init__.py +76 -0
  33. bub-0.6.0/src/bub/core/agent.py +822 -0
  34. bub-0.6.0/src/bub/core/codemode/__init__.py +306 -0
  35. bub-0.6.0/src/bub/core/codemode/republic_bridge.py +285 -0
  36. bub-0.5.0/src/bub/builtin/codemode/code_runner.py → bub-0.6.0/src/bub/core/codemode/runner.py +3 -3
  37. bub-0.6.0/src/bub/core/codemode/runner_child.py +584 -0
  38. bub-0.5.0/src/bub/builtin/codemode/__init__.py → bub-0.6.0/src/bub/core/codemode/stub.py +75 -108
  39. bub-0.6.0/src/bub/core/commands.py +64 -0
  40. bub-0.6.0/src/bub/core/context.py +70 -0
  41. bub-0.6.0/src/bub/core/events.py +350 -0
  42. bub-0.6.0/src/bub/core/model.py +83 -0
  43. bub-0.6.0/src/bub/core/recorder.py +92 -0
  44. {bub-0.5.0/src/bub → bub-0.6.0/src/bub/core}/store.py +1 -75
  45. bub-0.6.0/src/bub/core/system_prompt.py +91 -0
  46. {bub-0.5.0/src/bub → bub-0.6.0/src/bub/core}/tape.py +161 -172
  47. {bub-0.5.0/src/bub → bub-0.6.0/src/bub/core}/tools.py +205 -167
  48. bub-0.6.0/src/bub/environment.py +276 -0
  49. {bub-0.5.0 → bub-0.6.0}/src/bub/framework.py +172 -38
  50. bub-0.6.0/src/bub/hooks/agent.py +142 -0
  51. {bub-0.5.0 → bub-0.6.0}/src/bub/hooks/interception.py +62 -111
  52. {bub-0.5.0 → bub-0.6.0}/src/bub/hooks/runtime.py +9 -4
  53. {bub-0.5.0 → bub-0.6.0}/src/bub/hooks/specs.py +33 -19
  54. bub-0.6.0/src/bub/inquirer.py +96 -0
  55. bub-0.6.0/src/bub/program_status.py +36 -0
  56. bub-0.6.0/src/bub/prompt.py +58 -0
  57. bub-0.6.0/src/bub/sidecars.py +8 -0
  58. bub-0.6.0/src/bub/store.py +8 -0
  59. {bub-0.5.0 → bub-0.6.0}/src/bub/streaming.py +9 -2
  60. bub-0.6.0/src/bub/tape.py +8 -0
  61. bub-0.6.0/src/bub/tools.py +8 -0
  62. {bub-0.5.0 → bub-0.6.0}/src/bub/tracing.py +10 -7
  63. {bub-0.5.0 → bub-0.6.0}/src/bub/turn.py +5 -2
  64. {bub-0.5.0 → bub-0.6.0}/src/bub/utils.py +2 -2
  65. bub-0.6.0/src/skills/gh/SKILL.md +104 -0
  66. bub-0.6.0/tests/__init__.py +1 -0
  67. bub-0.6.0/tests/conftest.py +95 -0
  68. bub-0.6.0/tests/model_fakes.py +115 -0
  69. {bub-0.5.0 → bub-0.6.0}/tests/test_agent_hooks.py +140 -91
  70. bub-0.6.0/tests/test_agent_plugins.py +146 -0
  71. {bub-0.5.0 → bub-0.6.0}/tests/test_builtin_agent.py +149 -240
  72. {bub-0.5.0 → bub-0.6.0}/tests/test_builtin_cli.py +209 -47
  73. bub-0.6.0/tests/test_builtin_codex.py +234 -0
  74. {bub-0.5.0 → bub-0.6.0}/tests/test_builtin_hook_impl.py +74 -31
  75. {bub-0.5.0 → bub-0.6.0}/tests/test_builtin_tools.py +28 -44
  76. {bub-0.5.0 → bub-0.6.0}/tests/test_channels.py +230 -64
  77. bub-0.6.0/tests/test_cli_main.py +72 -0
  78. {bub-0.5.0 → bub-0.6.0}/tests/test_cli_renderer.py +3 -4
  79. {bub-0.5.0 → bub-0.6.0}/tests/test_codemode.py +317 -36
  80. bub-0.6.0/tests/test_compat_aliases.py +39 -0
  81. {bub-0.5.0 → bub-0.6.0}/tests/test_configure.py +12 -0
  82. bub-0.6.0/tests/test_core_agent.py +488 -0
  83. bub-0.6.0/tests/test_core_agent_step.py +547 -0
  84. bub-0.6.0/tests/test_core_boundary.py +43 -0
  85. bub-0.6.0/tests/test_core_codemode.py +141 -0
  86. {bub-0.5.0 → bub-0.6.0}/tests/test_environment.py +21 -6
  87. {bub-0.5.0 → bub-0.6.0}/tests/test_file_tape_store_entry_ids.py +3 -3
  88. bub-0.6.0/tests/test_file_tape_store_search.py +86 -0
  89. {bub-0.5.0 → bub-0.6.0}/tests/test_fork_store_merge_back.py +2 -2
  90. {bub-0.5.0 → bub-0.6.0}/tests/test_framework.py +150 -4
  91. {bub-0.5.0 → bub-0.6.0}/tests/test_hook_runtime.py +25 -0
  92. {bub-0.5.0 → bub-0.6.0}/tests/test_image_message.py +40 -66
  93. {bub-0.5.0 → bub-0.6.0}/tests/test_install_scripts.py +1 -1
  94. {bub-0.5.0 → bub-0.6.0}/tests/test_onboarding.py +135 -145
  95. {bub-0.5.0 → bub-0.6.0}/tests/test_otlp.py +1 -1
  96. bub-0.6.0/tests/test_program_status.py +97 -0
  97. bub-0.6.0/tests/test_provider_messages.py +259 -0
  98. {bub-0.5.0 → bub-0.6.0}/tests/test_sdk_isolation.py +77 -40
  99. {bub-0.5.0 → bub-0.6.0}/tests/test_session_settings.py +4 -4
  100. bub-0.6.0/tests/test_settings.py +453 -0
  101. {bub-0.5.0 → bub-0.6.0}/tests/test_shell_manager.py +26 -0
  102. {bub-0.5.0 → bub-0.6.0}/tests/test_spill.py +169 -83
  103. {bub-0.5.0 → bub-0.6.0}/tests/test_subagent_tool.py +6 -7
  104. bub-0.6.0/tests/test_tape.py +200 -0
  105. {bub-0.5.0 → bub-0.6.0}/tests/test_tape_search_output.py +1 -1
  106. bub-0.6.0/tests/test_tool_loading.py +269 -0
  107. bub-0.6.0/tests/test_tools.py +277 -0
  108. {bub-0.5.0 → bub-0.6.0}/tests/test_tracing.py +87 -141
  109. bub-0.6.0/tests/tool_fakes.py +10 -0
  110. bub-0.5.0/PKG-INFO +0 -221
  111. bub-0.5.0/README.md +0 -176
  112. bub-0.5.0/src/bub/__init__.py +0 -45
  113. bub-0.5.0/src/bub/__main__.py +0 -63
  114. bub-0.5.0/src/bub/builtin/__init__.py +0 -3
  115. bub-0.5.0/src/bub/builtin/agent.py +0 -596
  116. bub-0.5.0/src/bub/builtin/auth.py +0 -537
  117. bub-0.5.0/src/bub/builtin/codemode/code_runner_child.py +0 -176
  118. bub-0.5.0/src/bub/builtin/codex_provider.py +0 -497
  119. bub-0.5.0/src/bub/builtin/commands.py +0 -20
  120. bub-0.5.0/src/bub/builtin/context.py +0 -97
  121. bub-0.5.0/src/bub/builtin/environment.py +0 -145
  122. bub-0.5.0/src/bub/builtin/model_runner.py +0 -628
  123. bub-0.5.0/src/bub/environment.py +0 -140
  124. bub-0.5.0/src/bub/inquirer.py +0 -86
  125. bub-0.5.0/src/bub/types.py +0 -16
  126. bub-0.5.0/src/skills/gh/SKILL.md +0 -86
  127. bub-0.5.0/tests/conftest.py +0 -39
  128. bub-0.5.0/tests/test_builtin_codex.py +0 -506
  129. bub-0.5.0/tests/test_builtin_model_runner.py +0 -405
  130. bub-0.5.0/tests/test_settings.py +0 -194
  131. bub-0.5.0/tests/test_tape.py +0 -136
  132. bub-0.5.0/tests/test_tools.py +0 -290
  133. bub-0.5.0/tests/test_types.py +0 -20
  134. {bub-0.5.0 → bub-0.6.0}/.gitignore +0 -0
  135. {bub-0.5.0 → bub-0.6.0}/LICENSE +0 -0
  136. {bub-0.5.0 → bub-0.6.0}/src/bub/builtin/steering.py +0 -0
  137. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/__init__.py +0 -0
  138. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/admission.py +0 -0
  139. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/base.py +0 -0
  140. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/cli/ansi_bridge.py +0 -0
  141. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/cli/writers.py +0 -0
  142. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/contracts.py +0 -0
  143. {bub-0.5.0 → bub-0.6.0}/src/bub/channels/handler.py +0 -0
  144. {bub-0.5.0/src/bub → bub-0.6.0/src/bub/core}/sidecars.py +0 -0
  145. {bub-0.5.0 → bub-0.6.0}/src/bub/envelope.py +0 -0
  146. {bub-0.5.0 → bub-0.6.0}/src/bub/errors.py +0 -0
  147. {bub-0.5.0 → bub-0.6.0}/src/bub/gateway_installer.py +0 -0
  148. {bub-0.5.0 → bub-0.6.0}/src/bub/hooks/__init__.py +0 -0
  149. {bub-0.5.0 → bub-0.6.0}/src/bub/model_selection.py +0 -0
  150. {bub-0.5.0 → bub-0.6.0}/src/bub/skills.py +0 -0
  151. {bub-0.5.0 → bub-0.6.0}/src/skills/README.md +0 -0
  152. {bub-0.5.0 → bub-0.6.0}/src/skills/skill-creator/SKILL.md +0 -0
  153. {bub-0.5.0 → bub-0.6.0}/src/skills/skill-creator/license.txt +0 -0
  154. {bub-0.5.0 → bub-0.6.0}/src/skills/skill-creator/scripts/init_skill.py +0 -0
  155. {bub-0.5.0 → bub-0.6.0}/src/skills/skill-creator/scripts/quick_validate.py +0 -0
  156. {bub-0.5.0 → bub-0.6.0}/src/skills/telegram/SKILL.md +0 -0
  157. {bub-0.5.0 → bub-0.6.0}/src/skills/telegram/scripts/telegram_edit.py +0 -0
  158. {bub-0.5.0 → bub-0.6.0}/src/skills/telegram/scripts/telegram_rich.py +0 -0
  159. {bub-0.5.0 → bub-0.6.0}/src/skills/telegram/scripts/telegram_send.py +0 -0
  160. {bub-0.5.0 → bub-0.6.0}/tests/test_cli_help.py +0 -0
  161. {bub-0.5.0 → bub-0.6.0}/tests/test_envelope.py +0 -0
  162. {bub-0.5.0 → bub-0.6.0}/tests/test_errors.py +0 -0
  163. {bub-0.5.0 → bub-0.6.0}/tests/test_gateway_installer.py +0 -0
  164. {bub-0.5.0 → bub-0.6.0}/tests/test_skills.py +0 -0
  165. {bub-0.5.0 → bub-0.6.0}/tests/test_utils.py +0 -0
bub-0.6.0/PKG-INFO ADDED
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.5
2
+ Name: bub
3
+ Version: 0.6.0
4
+ Summary: A tiny agent runtime, composable with plugins.
5
+ Project-URL: Homepage, https://bub.build
6
+ Project-URL: Repository, https://github.com/bubbuild/bub
7
+ Project-URL: Documentation, https://bub.build
8
+ Author-email: Chojan Shang <psiace@apache.org>, Frost Ming <me@frostming.com>, Yihong <zouzou0208@gmail.com>
9
+ License: Apache-2.0
10
+ License-File: LICENSE
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: <4.0,>=3.12
19
+ Requires-Dist: loguru>=0.7.3
20
+ Requires-Dist: pydantic>=2.12.5
21
+ Requires-Dist: republic>=0.6.0a1
22
+ Requires-Dist: typing-extensions>=4.15.0
23
+ Provides-Extra: app
24
+ Requires-Dist: aiohttp>=3.14.4; extra == 'app'
25
+ Requires-Dist: httpx[socks]>=0.28.1; extra == 'app'
26
+ Requires-Dist: inquirer-textual>=0.8.0; extra == 'app'
27
+ Requires-Dist: pluggy>=1.6.0; extra == 'app'
28
+ Requires-Dist: prompt-toolkit>=3.0.52; extra == 'app'
29
+ Requires-Dist: pydantic-settings>=2.14.2; extra == 'app'
30
+ Requires-Dist: python-telegram-bot>=22.7; extra == 'app'
31
+ Requires-Dist: pyyaml>=6.0.3; extra == 'app'
32
+ Requires-Dist: rapidfuzz>=3.14.5; extra == 'app'
33
+ Requires-Dist: rich>=14.3.4; extra == 'app'
34
+ Requires-Dist: typer>=0.24.1; extra == 'app'
35
+ Provides-Extra: logfire
36
+ Requires-Dist: aiohttp>=3.14.4; extra == 'logfire'
37
+ Requires-Dist: httpx[socks]>=0.28.1; extra == 'logfire'
38
+ Requires-Dist: inquirer-textual>=0.8.0; extra == 'logfire'
39
+ Requires-Dist: logfire>=4.32.0; extra == 'logfire'
40
+ Requires-Dist: opentelemetry-api>=1.39.0; extra == 'logfire'
41
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.0; extra == 'logfire'
42
+ Requires-Dist: opentelemetry-sdk>=1.39.0; extra == 'logfire'
43
+ Requires-Dist: pluggy>=1.6.0; extra == 'logfire'
44
+ Requires-Dist: prompt-toolkit>=3.0.52; extra == 'logfire'
45
+ Requires-Dist: pydantic-settings>=2.14.2; extra == 'logfire'
46
+ Requires-Dist: python-telegram-bot>=22.7; extra == 'logfire'
47
+ Requires-Dist: pyyaml>=6.0.3; extra == 'logfire'
48
+ Requires-Dist: rapidfuzz>=3.14.5; extra == 'logfire'
49
+ Requires-Dist: rich>=14.3.4; extra == 'logfire'
50
+ Requires-Dist: typer>=0.24.1; extra == 'logfire'
51
+ Provides-Extra: trace
52
+ Requires-Dist: opentelemetry-api>=1.39.0; extra == 'trace'
53
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.0; extra == 'trace'
54
+ Requires-Dist: opentelemetry-sdk>=1.39.0; extra == 'trace'
55
+ Description-Content-Type: text/markdown
56
+
57
+ # Bub
58
+
59
+ <div align="center">
60
+
61
+ <picture>
62
+ <source srcset="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo-dark.png" media="(prefers-color-scheme: dark)">
63
+ <img alt="Bub logo" src="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo.png" width="200">
64
+ </picture>
65
+
66
+ <p><strong>Build your Bub.</strong></p>
67
+
68
+ [Website](https://bub.build) · [Docs](https://bub.build/docs/) · [Hub](https://hub.bub.build)
69
+
70
+ </div>
71
+
72
+ Put an agent in your own Python program, or customize the Bub application. The application uses the same agent kernel and adds configuration, plugins, and channel integration.
73
+
74
+ ## Build your own agent
75
+
76
+ Use `bub.core.Agent` to choose your model, tools, instructions, and conversation storage. The base `bub` package installs the kernel's dependencies.
77
+
78
+ In a Python 3.12+ project:
79
+
80
+ ```bash
81
+ uv add bub
82
+ ```
83
+
84
+ Run your first agent with the [SDK guide](https://bub.build/docs/sdk/), then [serve it with FastAPI](https://bub.build/docs/sdk/web-service/) when you need an HTTP endpoint.
85
+
86
+ You can also embed `BubAgent` to reuse the application's settings and plugin hooks in your service. This uses `bub[app]`; [Reuse the Bub app](https://bub.build/docs/integrations/reuse-app/) explains the integration choices and their requirements.
87
+
88
+ ## Customize the Bub app
89
+
90
+ Start a conversation, then add tools, skills, plugins, or channels for the work you want Bub to do.
91
+
92
+ Install on macOS or Linux:
93
+
94
+ ```bash
95
+ curl -fsSL https://bub.build/install.sh | bash
96
+ ```
97
+
98
+ On Windows:
99
+
100
+ ```powershell
101
+ powershell -ExecutionPolicy ByPass -c "irm https://bub.build/install.ps1 | iex"
102
+ ```
103
+
104
+ Follow the prompts to choose plugins and configure your model, then start a conversation:
105
+
106
+ ```bash
107
+ bub chat
108
+ ```
109
+
110
+ [Run your first conversation](https://bub.build/docs/app/workspace/) walks through a task in your workspace. [Customize the Bub app](https://bub.build/docs/app/workspace/) covers tools, plugins, and packaging. For `uv tool install` and other setup options, see [Install Bub](https://bub.build/docs/getting-started/install/#app-install).
111
+
112
+ ## Documentation
113
+
114
+ - [Choose a starting point](https://bub.build/docs/)
115
+ - [Shared concepts and capabilities](https://bub.build/docs/concepts/)
116
+ - [API and application reference](https://bub.build/docs/reference/)
117
+
118
+ ## Background
119
+
120
+ - [Why We Rewrote Bub](https://bub.build/posts/why-rewrite-bub/)
121
+ - [Socialized Evaluation and Agent Partnership](https://bub.build/posts/socialized-evaluation/)
122
+ - [Context from Tape](https://tape.systems)
123
+
124
+ ## License
125
+
126
+ [Apache-2.0](https://github.com/bubbuild/bub/blob/main/LICENSE)
bub-0.6.0/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Bub
2
+
3
+ <div align="center">
4
+
5
+ <picture>
6
+ <source srcset="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo-dark.png" media="(prefers-color-scheme: dark)">
7
+ <img alt="Bub logo" src="https://raw.githubusercontent.com/bubbuild/bub/refs/heads/main/website/src/assets/bub-logo.png" width="200">
8
+ </picture>
9
+
10
+ <p><strong>Build your Bub.</strong></p>
11
+
12
+ [Website](https://bub.build) · [Docs](https://bub.build/docs/) · [Hub](https://hub.bub.build)
13
+
14
+ </div>
15
+
16
+ Put an agent in your own Python program, or customize the Bub application. The application uses the same agent kernel and adds configuration, plugins, and channel integration.
17
+
18
+ ## Build your own agent
19
+
20
+ Use `bub.core.Agent` to choose your model, tools, instructions, and conversation storage. The base `bub` package installs the kernel's dependencies.
21
+
22
+ In a Python 3.12+ project:
23
+
24
+ ```bash
25
+ uv add bub
26
+ ```
27
+
28
+ Run your first agent with the [SDK guide](https://bub.build/docs/sdk/), then [serve it with FastAPI](https://bub.build/docs/sdk/web-service/) when you need an HTTP endpoint.
29
+
30
+ You can also embed `BubAgent` to reuse the application's settings and plugin hooks in your service. This uses `bub[app]`; [Reuse the Bub app](https://bub.build/docs/integrations/reuse-app/) explains the integration choices and their requirements.
31
+
32
+ ## Customize the Bub app
33
+
34
+ Start a conversation, then add tools, skills, plugins, or channels for the work you want Bub to do.
35
+
36
+ Install on macOS or Linux:
37
+
38
+ ```bash
39
+ curl -fsSL https://bub.build/install.sh | bash
40
+ ```
41
+
42
+ On Windows:
43
+
44
+ ```powershell
45
+ powershell -ExecutionPolicy ByPass -c "irm https://bub.build/install.ps1 | iex"
46
+ ```
47
+
48
+ Follow the prompts to choose plugins and configure your model, then start a conversation:
49
+
50
+ ```bash
51
+ bub chat
52
+ ```
53
+
54
+ [Run your first conversation](https://bub.build/docs/app/workspace/) walks through a task in your workspace. [Customize the Bub app](https://bub.build/docs/app/workspace/) covers tools, plugins, and packaging. For `uv tool install` and other setup options, see [Install Bub](https://bub.build/docs/getting-started/install/#app-install).
55
+
56
+ ## Documentation
57
+
58
+ - [Choose a starting point](https://bub.build/docs/)
59
+ - [Shared concepts and capabilities](https://bub.build/docs/concepts/)
60
+ - [API and application reference](https://bub.build/docs/reference/)
61
+
62
+ ## Background
63
+
64
+ - [Why We Rewrote Bub](https://bub.build/posts/why-rewrite-bub/)
65
+ - [Socialized Evaluation and Agent Partnership](https://bub.build/posts/socialized-evaluation/)
66
+ - [Context from Tape](https://tape.systems)
67
+
68
+ ## License
69
+
70
+ [Apache-2.0](https://github.com/bubbuild/bub/blob/main/LICENSE)
@@ -20,22 +20,11 @@ classifiers = [
20
20
  "Topic :: Software Development :: Libraries :: Python Modules",
21
21
  ]
22
22
 
23
+ # The agent kernel, bub.core. Everything else (framework, CLI, channels, builtin agent) is in the `app` extra.
23
24
  dependencies = [
25
+ "republic>=0.6.0a1",
24
26
  "pydantic>=2.12.5",
25
- "pydantic-settings>=2.14.2",
26
- "pyyaml>=6.0.3",
27
- "pluggy>=1.6.0",
28
- "inquirer-textual>=0.8.0",
29
- "typer>=0.24.1",
30
- "authlib>=1.7.2",
31
- "any-llm-sdk[anthropic]>=1.22.1",
32
- "rich>=14.3.4",
33
- "prompt-toolkit>=3.0.52",
34
- "python-telegram-bot>=22.7",
35
27
  "loguru>=0.7.3",
36
- "rapidfuzz>=3.14.5",
37
- "aiohttp>=3.14.3",
38
- "httpx[socks]>=0.28.1",
39
28
  "typing-extensions>=4.15.0",
40
29
  ]
41
30
 
@@ -45,21 +34,35 @@ Repository = "https://github.com/bubbuild/bub"
45
34
  Documentation = "https://bub.build"
46
35
 
47
36
  [project.scripts]
48
- bub = "bub.__main__:app"
37
+ bub = "bub.__main__:main"
49
38
 
50
39
  [project.optional-dependencies]
40
+ app = [
41
+ "pydantic-settings>=2.14.2",
42
+ "pyyaml>=6.0.3",
43
+ "pluggy>=1.6.0",
44
+ "inquirer-textual>=0.8.0",
45
+ "typer>=0.24.1",
46
+ "rich>=14.3.4",
47
+ "prompt-toolkit>=3.0.52",
48
+ "python-telegram-bot>=22.7",
49
+ "rapidfuzz>=3.14.5",
50
+ "aiohttp>=3.14.4",
51
+ "httpx[socks]>=0.28.1",
52
+ ]
51
53
  trace = [
52
54
  "opentelemetry-api>=1.39.0",
53
55
  "opentelemetry-sdk>=1.39.0",
54
56
  "opentelemetry-exporter-otlp-proto-http>=1.39.0",
55
57
  ]
56
58
  logfire = [
57
- "bub[trace]",
59
+ "bub[app,trace]",
58
60
  "logfire>=4.32.0",
59
61
  ]
60
62
 
61
63
  [dependency-groups]
62
64
  dev = [
65
+ "bub[app]",
63
66
  "pytest>=9.0.3",
64
67
  "tox-uv>=1.35.1",
65
68
  "types-PyYAML>=6.0.12.20260408",
@@ -0,0 +1,62 @@
1
+ """Bub framework package.
2
+
3
+ The top-level names are imported on first access, so ``import bub.core`` does not load
4
+ the framework, its settings or the CLI.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from importlib import import_module
11
+ from importlib.metadata import PackageNotFoundError
12
+ from importlib.metadata import version as metadata_version
13
+ from pathlib import Path
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ if TYPE_CHECKING:
17
+ from bub.configure import Settings, config, ensure_config
18
+ from bub.core.tools import tool
19
+ from bub.framework import BubFramework
20
+ from bub.hooks import hookimpl
21
+
22
+ home: Path
23
+
24
+ __all__ = [
25
+ "BubFramework",
26
+ "Settings",
27
+ "config",
28
+ "ensure_config",
29
+ "home",
30
+ "hookimpl",
31
+ "tool",
32
+ ]
33
+
34
+ _EXPORTS = {
35
+ "BubFramework": "bub.framework",
36
+ "Settings": "bub.configure",
37
+ "config": "bub.configure",
38
+ "ensure_config": "bub.configure",
39
+ "hookimpl": "bub.hooks",
40
+ "tool": "bub.core.tools",
41
+ }
42
+
43
+ try:
44
+ __version__ = import_module("bub._version").version
45
+ except ModuleNotFoundError:
46
+ try:
47
+ __version__ = metadata_version("bub")
48
+ except PackageNotFoundError:
49
+ __version__ = "0.0.0"
50
+
51
+
52
+ def __getattr__(name: str) -> Any:
53
+ if name == "home":
54
+ # Importing bub.configure loads ``.env``, which may set ``BUB_HOME``.
55
+ from bub.configure import DEFAULT_HOME
56
+
57
+ if "BUB_HOME" in os.environ:
58
+ return Path(os.path.expanduser(os.environ["BUB_HOME"]))
59
+ return DEFAULT_HOME
60
+ if name not in _EXPORTS:
61
+ raise AttributeError(f"module {__name__} has no attribute {name}")
62
+ return getattr(import_module(_EXPORTS[name]), name)
@@ -0,0 +1,101 @@
1
+ """Bub framework CLI bootstrap.
2
+
3
+ The CLI needs the ``app`` extra, so this module imports it only when the command runs:
4
+ ``main`` reports missing requirements instead of failing on an import.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import re
11
+ import sys
12
+ from importlib.metadata import PackageNotFoundError, distribution, requires
13
+ from typing import TYPE_CHECKING
14
+
15
+ if TYPE_CHECKING:
16
+ import typer
17
+
18
+ LOG_LEVEL = {
19
+ 0: "INFO",
20
+ 1: "DEBUG",
21
+ 2: "TRACE",
22
+ }
23
+
24
+ _APP_REQUIREMENT = re.compile(r"""^([A-Za-z0-9][A-Za-z0-9._-]*).*;.*\bextra\s*==\s*["']app["']""")
25
+
26
+
27
+ def missing_app_requirements() -> list[str]:
28
+ """Return the distributions required by ``bub[app]`` that are not installed."""
29
+ try:
30
+ requirements = requires("bub") or []
31
+ except PackageNotFoundError: # Running from a source tree that is not installed.
32
+ return []
33
+ missing: list[str] = []
34
+ for requirement in requirements:
35
+ if (match := _APP_REQUIREMENT.match(requirement)) is None:
36
+ continue
37
+ try:
38
+ distribution(match.group(1))
39
+ except PackageNotFoundError:
40
+ missing.append(match.group(1))
41
+ return missing
42
+
43
+
44
+ def _instrument_bub(level: str) -> None:
45
+ from loguru import logger
46
+
47
+ logger.remove()
48
+ logger.add(sys.stderr, level=level, colorize=True, diagnose=False)
49
+
50
+ if os.getenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") or os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT"):
51
+ from bub.tracing import configure_otlp
52
+
53
+ try:
54
+ configure_otlp()
55
+ except Exception as exc:
56
+ logger.warning("OTLP instrumentation disabled: {}", exc)
57
+ return
58
+
59
+ try:
60
+ import logfire
61
+ from logfire.integrations.loguru import LogfireHandler
62
+
63
+ logfire.configure()
64
+ logger.add(LogfireHandler(), level=level, format="{message}", diagnose=False)
65
+ except Exception as exc:
66
+ logger.debug("logfire instrumentation disabled: {}", exc)
67
+
68
+
69
+ def create_cli_app() -> typer.Typer:
70
+ import typer
71
+
72
+ from bub.builtin.settings import load_settings
73
+ from bub.framework import BubFramework
74
+
75
+ framework = BubFramework()
76
+ _instrument_bub(LOG_LEVEL[load_settings().verbose])
77
+ framework.load_hooks()
78
+ app = framework.create_cli_app()
79
+
80
+ if not app.registered_commands:
81
+
82
+ @app.command("help")
83
+ def _help() -> None:
84
+ typer.echo("No CLI command loaded.")
85
+
86
+ return app
87
+
88
+
89
+ def main() -> None:
90
+ """Run the ``bub`` command."""
91
+ if missing := missing_app_requirements():
92
+ sys.exit(
93
+ "The bub command needs the 'app' extra, which is not installed "
94
+ f"(missing: {', '.join(missing)}).\n"
95
+ "Install it with: uv tool install 'bub[app]' or pip install 'bub[app]'"
96
+ )
97
+ create_cli_app()()
98
+
99
+
100
+ if __name__ == "__main__":
101
+ main()
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.5.0'
22
- __version_tuple__ = version_tuple = (0, 5, 0)
21
+ __version__ = version = '0.6.0'
22
+ __version_tuple__ = version_tuple = (0, 6, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,35 @@
1
+ """CLI, channel work and prompt events published by the application."""
2
+
3
+ from contextvars import ContextVar
4
+ from dataclasses import dataclass
5
+ from typing import Literal
6
+
7
+ from bub.core.events import Event, EventBus
8
+
9
+ type Outcome = Literal["succeeded", "failed", "cancelled"]
10
+ type PromptKind = Literal["question", "permission", "auth"]
11
+
12
+ cli_events: ContextVar[EventBus | None] = ContextVar("cli_events", default=None)
13
+ """The event bus of the application running the current CLI command, if any."""
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class CommandChanged(Event):
18
+ """A CLI invocation started (None) or finished with an outcome."""
19
+
20
+ outcome: Outcome | None = None
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class WorkChanged(Event):
25
+ """A channel work snapshot, optionally including the message outcome that caused it."""
26
+
27
+ busy: bool
28
+ completed: Outcome | None = None
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class PromptChanged(Event):
33
+ """A modal prompt opened (kind) or closed (None)."""
34
+
35
+ kind: PromptKind | None
@@ -0,0 +1,6 @@
1
+ from .agent import BubAgent
2
+
3
+ Agent = BubAgent
4
+ """Deprecated alias of :class:`BubAgent`."""
5
+
6
+ __all__ = ["Agent", "BubAgent"]