bos-ai 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bos_ai-0.1.0/.gitignore +218 -0
- bos_ai-0.1.0/PKG-INFO +126 -0
- bos_ai-0.1.0/README.md +107 -0
- bos_ai-0.1.0/pyproject.toml +46 -0
- bos_ai-0.1.0/src/bos/__init__.py +0 -0
- bos_ai-0.1.0/src/bos/cli/commands/auth.py +130 -0
- bos_ai-0.1.0/src/bos/cli/commands/chat.py +112 -0
- bos_ai-0.1.0/src/bos/cli/commands/init.py +23 -0
- bos_ai-0.1.0/src/bos/cli/entry.py +52 -0
- bos_ai-0.1.0/src/bos/cli/tui_app.py +443 -0
- bos_ai-0.1.0/src/bos/config_template.toml +53 -0
- bos_ai-0.1.0/src/bos/core.py +1661 -0
- bos_ai-0.1.0/src/bos/exts.py +14 -0
- bos_ai-0.1.0/src/bos/mailboxes/__init__.py +3 -0
- bos_ai-0.1.0/src/bos/mailboxes/jsonl_mailbox.py +96 -0
- bos_ai-0.1.0/src/bos/memory_stores/__init__.py +0 -0
- bos_ai-0.1.0/src/bos/memory_stores/markdown_memory_store.py +55 -0
- bos_ai-0.1.0/src/bos/message_stores/__init__.py +0 -0
- bos_ai-0.1.0/src/bos/message_stores/jsonl_message_store.py +128 -0
- bos_ai-0.1.0/src/bos/providers/__init__.py +0 -0
- bos_ai-0.1.0/src/bos/providers/antigravity_provider.py +500 -0
- bos_ai-0.1.0/src/bos/providers/codex_provider.py +333 -0
- bos_ai-0.1.0/src/bos/providers/gemini_cli_provider.py +331 -0
- bos_ai-0.1.0/src/bos/providers/google_oauth.py +217 -0
- bos_ai-0.1.0/src/bos/tools/__init__.py +0 -0
- bos_ai-0.1.0/src/bos/tools/filesystem.py +306 -0
- bos_ai-0.1.0/src/bos/tools/knowledge.py +96 -0
- bos_ai-0.1.0/src/bos/tools/orchestration.py +57 -0
- bos_ai-0.1.0/src/bos/tools/system.py +143 -0
- bos_ai-0.1.0/tests/test_mailbox.py +118 -0
- bos_ai-0.1.0/uv.lock +1668 -0
bos_ai-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
.local/
|
|
2
|
+
|
|
3
|
+
# Byte-compiled / optimized / DLL files
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[codz]
|
|
6
|
+
*$py.class
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
share/python-wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
MANIFEST
|
|
30
|
+
|
|
31
|
+
# PyInstaller
|
|
32
|
+
# Usually these files are written by a python script from a template
|
|
33
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
34
|
+
*.manifest
|
|
35
|
+
*.spec
|
|
36
|
+
|
|
37
|
+
# Installer logs
|
|
38
|
+
pip-log.txt
|
|
39
|
+
pip-delete-this-directory.txt
|
|
40
|
+
|
|
41
|
+
# Unit test / coverage reports
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.nox/
|
|
45
|
+
.coverage
|
|
46
|
+
.coverage.*
|
|
47
|
+
.cache
|
|
48
|
+
nosetests.xml
|
|
49
|
+
coverage.xml
|
|
50
|
+
*.cover
|
|
51
|
+
*.py.cover
|
|
52
|
+
.hypothesis/
|
|
53
|
+
.pytest_cache/
|
|
54
|
+
cover/
|
|
55
|
+
|
|
56
|
+
# Translations
|
|
57
|
+
*.mo
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
local_settings.py
|
|
63
|
+
db.sqlite3
|
|
64
|
+
db.sqlite3-journal
|
|
65
|
+
|
|
66
|
+
# Flask stuff:
|
|
67
|
+
instance/
|
|
68
|
+
.webassets-cache
|
|
69
|
+
|
|
70
|
+
# Scrapy stuff:
|
|
71
|
+
.scrapy
|
|
72
|
+
|
|
73
|
+
# Sphinx documentation
|
|
74
|
+
docs/_build/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
.pybuilder/
|
|
78
|
+
target/
|
|
79
|
+
|
|
80
|
+
# Jupyter Notebook
|
|
81
|
+
.ipynb_checkpoints
|
|
82
|
+
|
|
83
|
+
# IPython
|
|
84
|
+
profile_default/
|
|
85
|
+
ipython_config.py
|
|
86
|
+
|
|
87
|
+
# pyenv
|
|
88
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
89
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
90
|
+
# .python-version
|
|
91
|
+
|
|
92
|
+
# pipenv
|
|
93
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
94
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
95
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
96
|
+
# install all needed dependencies.
|
|
97
|
+
# Pipfile.lock
|
|
98
|
+
|
|
99
|
+
# UV
|
|
100
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
101
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
102
|
+
# commonly ignored for libraries.
|
|
103
|
+
# uv.lock
|
|
104
|
+
|
|
105
|
+
# poetry
|
|
106
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
107
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
108
|
+
# commonly ignored for libraries.
|
|
109
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
110
|
+
# poetry.lock
|
|
111
|
+
# poetry.toml
|
|
112
|
+
|
|
113
|
+
# pdm
|
|
114
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
115
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
116
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
117
|
+
# pdm.lock
|
|
118
|
+
# pdm.toml
|
|
119
|
+
.pdm-python
|
|
120
|
+
.pdm-build/
|
|
121
|
+
|
|
122
|
+
# pixi
|
|
123
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
124
|
+
# pixi.lock
|
|
125
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
126
|
+
# in the .local directory. It is recommended not to include this directory in version control.
|
|
127
|
+
.pixi
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.local
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
201
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
203
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
bos_ai-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bos-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight single-file agent framework
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Requires-Dist: beautifulsoup4>=4.14.3
|
|
7
|
+
Requires-Dist: click>=8.1.7
|
|
8
|
+
Requires-Dist: filelock>=3.19.1
|
|
9
|
+
Requires-Dist: litellm==1.83.0
|
|
10
|
+
Requires-Dist: python-dotenv>=1.2.2
|
|
11
|
+
Requires-Dist: rich>=13.0.0
|
|
12
|
+
Requires-Dist: textual>=1.0.0
|
|
13
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
14
|
+
Provides-Extra: all
|
|
15
|
+
Requires-Dist: oauth-cli-kit>=0.1.3; extra == 'all'
|
|
16
|
+
Provides-Extra: providers
|
|
17
|
+
Requires-Dist: oauth-cli-kit>=0.1.3; extra == 'providers'
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# BOS AI
|
|
21
|
+
|
|
22
|
+
**Lightweight single-file agent framework**
|
|
23
|
+
|
|
24
|
+
`bos-ai` is an extensible, actor-based Python framework for building and running autonomous AI agents. Built around a remarkably lean core, it provides everything you need to run, extend, and orchestrate LLM-driven agents with local tool execution, memory, and message passing.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🚀 Easy Start
|
|
29
|
+
|
|
30
|
+
1. **Install the package:**
|
|
31
|
+
```bash
|
|
32
|
+
pip install bos-ai
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
2. **Initialize a Workspace:**
|
|
36
|
+
Navigate into your project directory and initialize the BOS AI workspace:
|
|
37
|
+
```bash
|
|
38
|
+
bos init
|
|
39
|
+
```
|
|
40
|
+
This command creates a `.bos` directory and a `config.toml` file to hold your project's agent configurations.
|
|
41
|
+
|
|
42
|
+
3. **Start Chatting:**
|
|
43
|
+
Use the chat command to interact with your agent:
|
|
44
|
+
```bash
|
|
45
|
+
bos chat
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 💻 CLI Intro
|
|
51
|
+
|
|
52
|
+
BOS AI ships with a `bos` CLI with lazy-loaded commands to keep startup times incredibly fast:
|
|
53
|
+
|
|
54
|
+
- **`bos init`**: Bootstraps a new workspace. It creates the `.bos/config.toml` file and provisions necessary data directories.
|
|
55
|
+
- **`bos auth`**: Set up authentication for various LLM providers and utilities.
|
|
56
|
+
- **`bos chat`**: Drops you into an interactive chat application to talk to the agents defined in your configuration. You can also use it in "oneshot" mode.
|
|
57
|
+
|
|
58
|
+
**LLM Providers via Auth:**
|
|
59
|
+
```bash
|
|
60
|
+
# Chat with the Antigravity provider (requires `bos auth antigravity`)
|
|
61
|
+
bos chat -M "hello" -m antigravity/gemini-3.1-pro-low -a main
|
|
62
|
+
|
|
63
|
+
# Chat with the Gemini CLI provider (requires `bos auth gemini-cli`)
|
|
64
|
+
bos chat -M "hello" -m gemini-cli/gemini-2.5-flash -a main
|
|
65
|
+
|
|
66
|
+
# Chat with the Codex provider (requires `bos auth codex`)
|
|
67
|
+
bos chat -M "hello" -m codex/gpt-5.3-codex -a main
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Global Options:**
|
|
71
|
+
- `-w`, `--workspace`: Path to the workspace directory (defaults to `.`).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🧠 Principles
|
|
76
|
+
|
|
77
|
+
`bos-ai` is built on a few core design principles:
|
|
78
|
+
|
|
79
|
+
- **Lightweight & Embeddable**: The heart of the framework lives in a single, comprehensive file (`core.py`), ensuring that complexity is minimized while keeping the abstractions powerfully dense.
|
|
80
|
+
- **Extensible at the Core**: Every significant layer—from LLM providers, to message persistence, to memory and tools—is powered by an internal Extension System.
|
|
81
|
+
- **Agent as an Actor**: Agents communicate via asynchronous message passing (the `Mailbox` protocol). This enables robust multi-agent orchestration without tightly coupled code.
|
|
82
|
+
- **Harness-Managed Lifecycle**: An `AgentHarness` is used to bootstrap, maintain, and gracefully tear down shared resources (like databases or API connections) across all agents in the workspace.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 🔌 Extension Framework
|
|
87
|
+
|
|
88
|
+
BOS AI utilizes an `ExtensionPoint` pattern for its modular capabilities. You can seamlessly inject your own logic or override defaults decorators.
|
|
89
|
+
|
|
90
|
+
The framework provides named extension points such as:
|
|
91
|
+
- `@ep_provider`: Connect new LLM backends (OpenAI, Anthropic, Gemini, etc.).
|
|
92
|
+
- `@ep_tool`: Add new conversational tools that the LLM can invoke.
|
|
93
|
+
- `@ep_memory_store`: Connect alternative vector databases or key-value stores.
|
|
94
|
+
- `@ep_message_store`: Custom persistence logic for conversation history.
|
|
95
|
+
- `@ep_mailbox`: Implement distributed message-passing interfaces like Redis or RabbitMQ.
|
|
96
|
+
- `@ep_react_interceptor`: Hooks to orchestrate the internal ReAct loop of an agent.
|
|
97
|
+
|
|
98
|
+
Example registering a custom tool:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from bos.core import ep_tool
|
|
102
|
+
|
|
103
|
+
@ep_tool(
|
|
104
|
+
name="my_custom_tool",
|
|
105
|
+
description="Does something awesome.",
|
|
106
|
+
# ... additional structured metadata ...
|
|
107
|
+
)
|
|
108
|
+
async def my_custom_tool(arg1: str):
|
|
109
|
+
return f"Processed {arg1}"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
To load your extensions, simply add their module paths to the `platform.extensions` array in your workspace's `config.toml`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## ⚙️ Configuration System
|
|
117
|
+
|
|
118
|
+
BOS AI uses a hierarchical, TOML-based configuration pattern that is specifically designed for isolation per-workspace.
|
|
119
|
+
|
|
120
|
+
When you run a command, `bos` searches upwards from the current directory to find a `.bos/config.toml` file, eventually falling back to a global `~/.bos/config.toml` if none is found.
|
|
121
|
+
|
|
122
|
+
### Config Structure (`.bos/config.toml`)
|
|
123
|
+
- **`[platform]`**: Define environment variables, `.env` file locations, and structural extensions loading rules.
|
|
124
|
+
- **`[[platform.agents]]`**: Array of dictionaries defining your agents. You can configure `system_prompt`, limits (`max_tokens`), required `tools`, `skills`, memory definitions, and even `subagents`.
|
|
125
|
+
- **`[harness]`**: Define the overarching services all agents in the environment share. For example, configure the active `memory_store` directory or hook up an interceptor chain.
|
|
126
|
+
- **`[cli]`**: Directives and default options for the command-line application (like specifying a default agent target).
|
bos_ai-0.1.0/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# BOS AI
|
|
2
|
+
|
|
3
|
+
**Lightweight single-file agent framework**
|
|
4
|
+
|
|
5
|
+
`bos-ai` is an extensible, actor-based Python framework for building and running autonomous AI agents. Built around a remarkably lean core, it provides everything you need to run, extend, and orchestrate LLM-driven agents with local tool execution, memory, and message passing.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🚀 Easy Start
|
|
10
|
+
|
|
11
|
+
1. **Install the package:**
|
|
12
|
+
```bash
|
|
13
|
+
pip install bos-ai
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. **Initialize a Workspace:**
|
|
17
|
+
Navigate into your project directory and initialize the BOS AI workspace:
|
|
18
|
+
```bash
|
|
19
|
+
bos init
|
|
20
|
+
```
|
|
21
|
+
This command creates a `.bos` directory and a `config.toml` file to hold your project's agent configurations.
|
|
22
|
+
|
|
23
|
+
3. **Start Chatting:**
|
|
24
|
+
Use the chat command to interact with your agent:
|
|
25
|
+
```bash
|
|
26
|
+
bos chat
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 💻 CLI Intro
|
|
32
|
+
|
|
33
|
+
BOS AI ships with a `bos` CLI with lazy-loaded commands to keep startup times incredibly fast:
|
|
34
|
+
|
|
35
|
+
- **`bos init`**: Bootstraps a new workspace. It creates the `.bos/config.toml` file and provisions necessary data directories.
|
|
36
|
+
- **`bos auth`**: Set up authentication for various LLM providers and utilities.
|
|
37
|
+
- **`bos chat`**: Drops you into an interactive chat application to talk to the agents defined in your configuration. You can also use it in "oneshot" mode.
|
|
38
|
+
|
|
39
|
+
**LLM Providers via Auth:**
|
|
40
|
+
```bash
|
|
41
|
+
# Chat with the Antigravity provider (requires `bos auth antigravity`)
|
|
42
|
+
bos chat -M "hello" -m antigravity/gemini-3.1-pro-low -a main
|
|
43
|
+
|
|
44
|
+
# Chat with the Gemini CLI provider (requires `bos auth gemini-cli`)
|
|
45
|
+
bos chat -M "hello" -m gemini-cli/gemini-2.5-flash -a main
|
|
46
|
+
|
|
47
|
+
# Chat with the Codex provider (requires `bos auth codex`)
|
|
48
|
+
bos chat -M "hello" -m codex/gpt-5.3-codex -a main
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Global Options:**
|
|
52
|
+
- `-w`, `--workspace`: Path to the workspace directory (defaults to `.`).
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🧠 Principles
|
|
57
|
+
|
|
58
|
+
`bos-ai` is built on a few core design principles:
|
|
59
|
+
|
|
60
|
+
- **Lightweight & Embeddable**: The heart of the framework lives in a single, comprehensive file (`core.py`), ensuring that complexity is minimized while keeping the abstractions powerfully dense.
|
|
61
|
+
- **Extensible at the Core**: Every significant layer—from LLM providers, to message persistence, to memory and tools—is powered by an internal Extension System.
|
|
62
|
+
- **Agent as an Actor**: Agents communicate via asynchronous message passing (the `Mailbox` protocol). This enables robust multi-agent orchestration without tightly coupled code.
|
|
63
|
+
- **Harness-Managed Lifecycle**: An `AgentHarness` is used to bootstrap, maintain, and gracefully tear down shared resources (like databases or API connections) across all agents in the workspace.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🔌 Extension Framework
|
|
68
|
+
|
|
69
|
+
BOS AI utilizes an `ExtensionPoint` pattern for its modular capabilities. You can seamlessly inject your own logic or override defaults decorators.
|
|
70
|
+
|
|
71
|
+
The framework provides named extension points such as:
|
|
72
|
+
- `@ep_provider`: Connect new LLM backends (OpenAI, Anthropic, Gemini, etc.).
|
|
73
|
+
- `@ep_tool`: Add new conversational tools that the LLM can invoke.
|
|
74
|
+
- `@ep_memory_store`: Connect alternative vector databases or key-value stores.
|
|
75
|
+
- `@ep_message_store`: Custom persistence logic for conversation history.
|
|
76
|
+
- `@ep_mailbox`: Implement distributed message-passing interfaces like Redis or RabbitMQ.
|
|
77
|
+
- `@ep_react_interceptor`: Hooks to orchestrate the internal ReAct loop of an agent.
|
|
78
|
+
|
|
79
|
+
Example registering a custom tool:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from bos.core import ep_tool
|
|
83
|
+
|
|
84
|
+
@ep_tool(
|
|
85
|
+
name="my_custom_tool",
|
|
86
|
+
description="Does something awesome.",
|
|
87
|
+
# ... additional structured metadata ...
|
|
88
|
+
)
|
|
89
|
+
async def my_custom_tool(arg1: str):
|
|
90
|
+
return f"Processed {arg1}"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To load your extensions, simply add their module paths to the `platform.extensions` array in your workspace's `config.toml`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## ⚙️ Configuration System
|
|
98
|
+
|
|
99
|
+
BOS AI uses a hierarchical, TOML-based configuration pattern that is specifically designed for isolation per-workspace.
|
|
100
|
+
|
|
101
|
+
When you run a command, `bos` searches upwards from the current directory to find a `.bos/config.toml` file, eventually falling back to a global `~/.bos/config.toml` if none is found.
|
|
102
|
+
|
|
103
|
+
### Config Structure (`.bos/config.toml`)
|
|
104
|
+
- **`[platform]`**: Define environment variables, `.env` file locations, and structural extensions loading rules.
|
|
105
|
+
- **`[[platform.agents]]`**: Array of dictionaries defining your agents. You can configure `system_prompt`, limits (`max_tokens`), required `tools`, `skills`, memory definitions, and even `subagents`.
|
|
106
|
+
- **`[harness]`**: Define the overarching services all agents in the environment share. For example, configure the active `memory_store` directory or hook up an interceptor chain.
|
|
107
|
+
- **`[cli]`**: Directives and default options for the command-line application (like specifying a default agent target).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "bos-ai"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Lightweight single-file agent framework"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"litellm==1.83.0",
|
|
9
|
+
"python-dotenv>=1.2.2",
|
|
10
|
+
"filelock>=3.19.1",
|
|
11
|
+
"click>=8.1.7",
|
|
12
|
+
"rich>=13.0.0",
|
|
13
|
+
"textual>=1.0.0",
|
|
14
|
+
"tomli>=2.0.0; python_version<'3.11'",
|
|
15
|
+
"beautifulsoup4>=4.14.3",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
bos = "bos.cli.entry:main"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
providers = [
|
|
23
|
+
"oauth-cli-kit>=0.1.3",
|
|
24
|
+
]
|
|
25
|
+
all = [
|
|
26
|
+
"oauth-cli-kit>=0.1.3",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["hatchling"]
|
|
31
|
+
build-backend = "hatchling.build"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/bos"]
|
|
35
|
+
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8.4.1",
|
|
39
|
+
"pytest-asyncio>=1.1.0",
|
|
40
|
+
"pytest-cov>=6.2.1",
|
|
41
|
+
"ruff>=0.12.4",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.ruff]
|
|
45
|
+
line-length = 120
|
|
46
|
+
lint.select = ["E", "F", "I"]
|
|
File without changes
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from bos.core import _flock
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group(name="auth")
|
|
9
|
+
def auth():
|
|
10
|
+
"""Manage authentication for BOS AI."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@auth.command(name="codex")
|
|
15
|
+
@click.option("--name", default="default", help="Name of the credential.")
|
|
16
|
+
def codex(name: str):
|
|
17
|
+
"""Authenticate with OpenAI Codex."""
|
|
18
|
+
try:
|
|
19
|
+
from oauth_cli_kit import get_token, login_oauth_interactive
|
|
20
|
+
except ImportError:
|
|
21
|
+
raise click.ClickException("oauth_cli_kit not installed. Run: uv pip install oauth-cli-kit")
|
|
22
|
+
|
|
23
|
+
creds_dir = Path.home() / ".config" / "bos"
|
|
24
|
+
creds_dir.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
token_path = creds_dir / f"codex_auth.{name}.json"
|
|
27
|
+
from oauth_cli_kit.storage import FileTokenStorage
|
|
28
|
+
|
|
29
|
+
storage = FileTokenStorage(str(token_path))
|
|
30
|
+
|
|
31
|
+
token = None
|
|
32
|
+
try:
|
|
33
|
+
token = get_token(storage=storage)
|
|
34
|
+
except Exception:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
if not (token and token.access):
|
|
38
|
+
click.echo("Starting interactive OAuth login...\n")
|
|
39
|
+
token = login_oauth_interactive(
|
|
40
|
+
print_fn=lambda s: click.echo(s),
|
|
41
|
+
prompt_fn=lambda s: click.prompt(s),
|
|
42
|
+
originator="tradingdesk",
|
|
43
|
+
storage=storage,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if not (token and token.access):
|
|
47
|
+
raise click.ClickException("Authentication failed")
|
|
48
|
+
|
|
49
|
+
click.echo(f"\n✓ Authenticated with OpenAI Codex ({getattr(token, 'account_id', '') or name})")
|
|
50
|
+
click.echo(f" Credentials saved to: {token_path}")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@auth.command(name="antigravity")
|
|
54
|
+
@click.option("--name", default="default", help="Name of the credential.")
|
|
55
|
+
def antigravity(name: str):
|
|
56
|
+
"""Authenticate with Google Antigravity."""
|
|
57
|
+
import asyncio
|
|
58
|
+
import json
|
|
59
|
+
import webbrowser
|
|
60
|
+
|
|
61
|
+
from bos.providers.antigravity_provider import login_antigravity
|
|
62
|
+
|
|
63
|
+
creds_dir = Path.home() / ".config" / "bos"
|
|
64
|
+
creds_dir.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
token_path = creds_dir / f"antigravity_auth.{name}.json"
|
|
66
|
+
|
|
67
|
+
def on_url(url: str, msg: str):
|
|
68
|
+
click.echo(f"{msg}\n\n {url}\n")
|
|
69
|
+
try:
|
|
70
|
+
webbrowser.open(url)
|
|
71
|
+
except Exception:
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
creds = asyncio.run(
|
|
76
|
+
login_antigravity(
|
|
77
|
+
on_auth=on_url,
|
|
78
|
+
on_progress=lambda msg: click.echo(f" {msg}"),
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
with _flock(token_path):
|
|
82
|
+
token_path.write_text(json.dumps(dict(creds.__dict__)))
|
|
83
|
+
click.echo(f"\n✓ Authenticated with Google Antigravity ({creds.email or ''})")
|
|
84
|
+
click.echo(f" Credentials saved to: {token_path}")
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise click.ClickException(f"Authentication failed: {e}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@auth.command(name="gemini-cli")
|
|
90
|
+
@click.option("--name", default="default", help="Name of the credential.")
|
|
91
|
+
def gemini_cli(name: str) -> None:
|
|
92
|
+
"""Authenticate with Gemini CLI.
|
|
93
|
+
|
|
94
|
+
This command initiates an interactive OAuth 2.0 PKCE flow to authenticate with
|
|
95
|
+
Google Cloud Code Assist using your personal Google account.
|
|
96
|
+
"""
|
|
97
|
+
import asyncio
|
|
98
|
+
import json
|
|
99
|
+
import webbrowser
|
|
100
|
+
|
|
101
|
+
from bos.providers.gemini_cli_provider import login_gemini_cli
|
|
102
|
+
|
|
103
|
+
click.echo("\n" + "=" * 50)
|
|
104
|
+
click.echo(" Gemini CLI Authentication")
|
|
105
|
+
click.echo("=" * 50)
|
|
106
|
+
|
|
107
|
+
creds_dir = Path.home() / ".config" / "bos"
|
|
108
|
+
creds_dir.mkdir(parents=True, exist_ok=True)
|
|
109
|
+
token_path = creds_dir / f"gemini_cli_auth.{name}.json"
|
|
110
|
+
|
|
111
|
+
def on_url(url: str, msg: str):
|
|
112
|
+
click.echo(f"{msg}\n\n {url}\n")
|
|
113
|
+
try:
|
|
114
|
+
webbrowser.open(url)
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
creds = asyncio.run(
|
|
120
|
+
login_gemini_cli(
|
|
121
|
+
on_auth=on_url,
|
|
122
|
+
on_progress=lambda msg: click.echo(f" {msg}"),
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
with _flock(token_path):
|
|
126
|
+
token_path.write_text(json.dumps(dict(creds.__dict__)))
|
|
127
|
+
click.echo(f"\n✓ Authenticated with Gemini CLI ({creds.email or ''})")
|
|
128
|
+
click.echo(f" Credentials saved to: {token_path}")
|
|
129
|
+
except Exception as e:
|
|
130
|
+
raise click.ClickException(f"Authentication failed: {e}")
|