byte-ai-cli 0.1.8__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.
- byte_ai_cli-0.1.8/PKG-INFO +166 -0
- byte_ai_cli-0.1.8/README.md +128 -0
- byte_ai_cli-0.1.8/pyproject.toml +136 -0
- byte_ai_cli-0.1.8/src/byte/__init__.py +4 -0
- byte_ai_cli-0.1.8/src/byte/bootstrap.py +91 -0
- byte_ai_cli-0.1.8/src/byte/container.py +90 -0
- byte_ai_cli-0.1.8/src/byte/context.py +22 -0
- byte_ai_cli-0.1.8/src/byte/core/__init__.py +4 -0
- byte_ai_cli-0.1.8/src/byte/core/array_store.py +82 -0
- byte_ai_cli-0.1.8/src/byte/core/cli.py +22 -0
- byte_ai_cli-0.1.8/src/byte/core/config/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/core/config/config.py +81 -0
- byte_ai_cli-0.1.8/src/byte/core/event_bus.py +92 -0
- byte_ai_cli-0.1.8/src/byte/core/exceptions.py +19 -0
- byte_ai_cli-0.1.8/src/byte/core/initializer.py +209 -0
- byte_ai_cli-0.1.8/src/byte/core/logging.py +34 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/bootable.py +66 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/conditionable.py +53 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/configurable.py +19 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/eventable.py +34 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/injectable.py +28 -0
- byte_ai_cli-0.1.8/src/byte/core/mixins/user_interactive.py +105 -0
- byte_ai_cli-0.1.8/src/byte/core/service/base_service.py +58 -0
- byte_ai_cli-0.1.8/src/byte/core/service_provider.py +103 -0
- byte_ai_cli-0.1.8/src/byte/core/task_manager.py +28 -0
- byte_ai_cli-0.1.8/src/byte/core/utils/__init__.py +108 -0
- byte_ai_cli-0.1.8/src/byte/core/utils/save_fixture.py +27 -0
- byte_ai_cli-0.1.8/src/byte/domain/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/command/ask_command.py +34 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/ask/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/ask/agent.py +113 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/ask/prompts.py +24 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/base.py +168 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/cleaner/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/cleaner/agent.py +163 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/cleaner/prompt.py +30 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/coder/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/coder/agent.py +116 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/coder/prompts.py +30 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/commit/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/commit/agent.py +84 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/commit/prompt.py +32 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/copy/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/copy/agent.py +44 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/fixer/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/fixer/agent.py +29 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/fixer/prompts.py +30 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/research/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/research/agent.py +101 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/implementations/research/prompts.py +37 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/assistant_node.py +46 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/base_node.py +12 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/copy_node.py +168 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/end_node.py +29 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/lint_node.py +18 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/parse_blocks_node.py +58 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/start_node.py +34 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/nodes/tool_node.py +51 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/schemas.py +25 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/service/agent_service.py +72 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/service_provider.py +71 -0
- byte_ai_cli-0.1.8/src/byte/domain/agent/state.py +57 -0
- byte_ai_cli-0.1.8/src/byte/domain/analytics/service/agent_analytics_service.py +199 -0
- byte_ai_cli-0.1.8/src/byte/domain/analytics/service_provider.py +44 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/config.py +16 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/rich/heading.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/rich/markdown.py +48 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/rich/menu.py +563 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/rich/rune_spinner.py +73 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/schemas.py +156 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service/command_registry.py +122 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service/console_service.py +305 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service/interactions_service.py +159 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service/prompt_toolkit_service.py +193 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service/stream_rendering_service.py +271 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/service_provider.py +71 -0
- byte_ai_cli-0.1.8/src/byte/domain/cli/utils/formatters.py +122 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/command/save_recording_command.py +28 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/command/start_recording_command.py +20 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/command/test_command.py +37 -0
- byte_ai_cli-0.1.8/src/byte/domain/development/service_provider.py +33 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/command/copy_command.py +34 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/config.py +10 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/exceptions.py +44 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/models.py +81 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/edit_block_prompt.py +271 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/edit_block_service.py +355 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/edit_format_service.py +85 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/shell_command_prompt.py +96 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service/shell_command_service.py +211 -0
- byte_ai_cli-0.1.8/src/byte/domain/edit_format/service_provider.py +53 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/command/add_file_command.py +57 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/command/add_read_only_file_command.py +53 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/command/drop_file_command.py +62 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/command/list_files_command.py +64 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/config.py +18 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/schemas.py +37 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service/discovery_service.py +163 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service/file_service.py +363 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service/ignore_service.py +93 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service/watcher_service.py +356 -0
- byte_ai_cli-0.1.8/src/byte/domain/files/service_provider.py +68 -0
- byte_ai_cli-0.1.8/src/byte/domain/git/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/git/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/git/command/commit_command.py +68 -0
- byte_ai_cli-0.1.8/src/byte/domain/git/service/git_service.py +143 -0
- byte_ai_cli-0.1.8/src/byte/domain/git/service_provider.py +22 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/command/context_drop_command.py +55 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/command/context_list_command.py +36 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/command/web_command.py +96 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/service/cli_context_display_service.py +53 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/service/convention_context_service.py +67 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/service/session_context_service.py +89 -0
- byte_ai_cli-0.1.8/src/byte/domain/knowledge/service_provider.py +64 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/command/lint_command.py +45 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/config.py +19 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/exceptions.py +12 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/service/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/service/lint_service.py +285 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/service_provider.py +23 -0
- byte_ai_cli-0.1.8/src/byte/domain/lint/types.py +23 -0
- byte_ai_cli-0.1.8/src/byte/domain/llm/config.py +61 -0
- byte_ai_cli-0.1.8/src/byte/domain/llm/schemas.py +188 -0
- byte_ai_cli-0.1.8/src/byte/domain/llm/service/llm_service.py +71 -0
- byte_ai_cli-0.1.8/src/byte/domain/llm/service_provider.py +36 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/command/mcp_tool_command.py +111 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/config.py +48 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/service/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/service/mcp_service.py +101 -0
- byte_ai_cli-0.1.8/src/byte/domain/mcp/service_provider.py +28 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/command/clear_command.py +45 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/command/reset_command.py +47 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/service/memory_service.py +79 -0
- byte_ai_cli-0.1.8/src/byte/domain/memory/service_provider.py +24 -0
- byte_ai_cli-0.1.8/src/byte/domain/system/command/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/system/command/exit_command.py +25 -0
- byte_ai_cli-0.1.8/src/byte/domain/system/command/initilizie_command.py +78 -0
- byte_ai_cli-0.1.8/src/byte/domain/system/service/system_context_service.py +54 -0
- byte_ai_cli-0.1.8/src/byte/domain/system/service_provider.py +45 -0
- byte_ai_cli-0.1.8/src/byte/domain/tools/__init__.py +3 -0
- byte_ai_cli-0.1.8/src/byte/domain/tools/read_file.py +50 -0
- byte_ai_cli-0.1.8/src/byte/domain/tools/ripgrep_search.py +71 -0
- byte_ai_cli-0.1.8/src/byte/domain/tools/service_provider.py +13 -0
- byte_ai_cli-0.1.8/src/byte/domain/tools/user_confirm.py +20 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/config.py +21 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/exceptions.py +17 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/service/__init__.py +0 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/service/chromium_service.py +55 -0
- byte_ai_cli-0.1.8/src/byte/domain/web/service_provider.py +17 -0
- byte_ai_cli-0.1.8/src/byte/main.py +74 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: byte-ai-cli
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: A human-in-the-loop AI coding agent that keeps you in control.
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Intended Audience :: Developers
|
|
7
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Topic :: Software Development
|
|
14
|
+
Requires-Dist: pyperclip>=1.9.0
|
|
15
|
+
Requires-Dist: aiosqlite>=0.21.0
|
|
16
|
+
Requires-Dist: beautifulsoup4>=4.14.2
|
|
17
|
+
Requires-Dist: click>=8.2.1
|
|
18
|
+
Requires-Dist: gitpython>=3.1.45
|
|
19
|
+
Requires-Dist: langchain-mcp-adapters>=0.1.10
|
|
20
|
+
Requires-Dist: langchain[anthropic,google-genai,openai]>=0.3.27
|
|
21
|
+
Requires-Dist: langgraph>=0.6.7
|
|
22
|
+
Requires-Dist: langgraph-checkpoint-sqlite>=2.0.11
|
|
23
|
+
Requires-Dist: markdownify>=1.2.0
|
|
24
|
+
Requires-Dist: pathspec>=0.12.1
|
|
25
|
+
Requires-Dist: prompt-toolkit>=3.0.52
|
|
26
|
+
Requires-Dist: pydantic>=2.11.7
|
|
27
|
+
Requires-Dist: pydantic-settings>=2.10.1
|
|
28
|
+
Requires-Dist: pydoll-python>=2.8.2
|
|
29
|
+
Requires-Dist: pyperclip>=1.11.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.1.1
|
|
31
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
32
|
+
Requires-Dist: rich>=14.1.0
|
|
33
|
+
Requires-Dist: watchfiles>=1.1.0
|
|
34
|
+
Requires-Dist: loguru>=0.7.3
|
|
35
|
+
Requires-Python: >=3.12
|
|
36
|
+
Project-URL: Homepage, https://github.com/UseTheFork/byte
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# Byte
|
|
40
|
+
|
|
41
|
+
<p align="center"><img alt="Byte Logo" src="docs/images/logo.svg" /></p>
|
|
42
|
+
|
|
43
|
+
A human-in-the-loop AI coding agent that keeps you in control. Byte helps you build through natural conversation while maintaining full visibility and approval over every change.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## What is Byte?
|
|
48
|
+
|
|
49
|
+
Byte is a CLI coding agent designed for developers who want AI assistance without sacrificing control. Unlike autonomous agents that make multiple decisions and tool calls independently, Byte requires your approval for every decision.
|
|
50
|
+
|
|
51
|
+
**Key Features:**
|
|
52
|
+
|
|
53
|
+
- Review and confirm every change before it's applied
|
|
54
|
+
- See exactly what the agent modifies in your code
|
|
55
|
+
- Manage precisely what information the AI receives
|
|
56
|
+
- Slots into your existing development environment
|
|
57
|
+
- Structured prompts that adapt and evolve with each interaction
|
|
58
|
+
- Automatic linting, formatting, and testing without extra commands
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Design Philosophy
|
|
63
|
+
|
|
64
|
+
**Transparency First** - You see the complete prompt, not just your input. All interactions are logged for reference and debugging.
|
|
65
|
+
|
|
66
|
+
**Explicit Over Implicit** - Changes require approval. Context additions need confirmation. No surprises.
|
|
67
|
+
|
|
68
|
+
**Complementary, Not Replacement** - Byte enhances your workflow without replacing your tools or editor.
|
|
69
|
+
|
|
70
|
+
**Quality Over Quantity** - Better prompts produce better results. Byte prioritizes well-structured instructions over large context windows.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
Get started with Byte in three steps:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Install with uv
|
|
80
|
+
$ uv tool install byte
|
|
81
|
+
|
|
82
|
+
# Navigate to your project
|
|
83
|
+
$ cd /path/to/your/project
|
|
84
|
+
|
|
85
|
+
# Run Byte
|
|
86
|
+
$ byte
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See the [Installation Guide](<[getting-started/installation.md](https://usethefork.github.io/byte/getting-started/installation/)>) for other installation methods including pip and Nix.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Why This Approach?
|
|
94
|
+
|
|
95
|
+
### Human-in-the-Loop Design
|
|
96
|
+
|
|
97
|
+
Every decision and code change requires your confirmation. If you prefer agents that work autonomously, Byte isn't for you. If you value control and transparency, you'll appreciate the deliberate confirmation flow.
|
|
98
|
+
|
|
99
|
+
### Built for Experienced Developers
|
|
100
|
+
|
|
101
|
+
Designed for experienced developers who understand good design principles. This isn't a tool where you provide a specification and it builds the entire feature. Instead, Byte excels at small, incremental changes that keep you in control. Understanding when to refactor, how to structure code, and what constitutes good design remains your responsibility.
|
|
102
|
+
|
|
103
|
+
### Search/Replace Over Tools
|
|
104
|
+
|
|
105
|
+
Instead of giving the AI arbitrary tools, explicit Search/Replace blocks show you the exact changes before they happen, making it easy to cancel or modify the proposed work.
|
|
106
|
+
|
|
107
|
+
### Workflow Preservation
|
|
108
|
+
|
|
109
|
+
Your editor stays central to development. Whether you use Vim, VS Code, or Jetbrains, Byte complements your existing workflow as something you invoke when needed.
|
|
110
|
+
|
|
111
|
+
### Context Management
|
|
112
|
+
|
|
113
|
+
You control exactly what context the LLM receives:
|
|
114
|
+
|
|
115
|
+
- Add or remove files from the active context
|
|
116
|
+
- Monitor token usage and memory consumption
|
|
117
|
+
- Prevent context overflow with targeted information
|
|
118
|
+
|
|
119
|
+
### Intelligent Prompting
|
|
120
|
+
|
|
121
|
+
Structured prompts adapt with each turn:
|
|
122
|
+
|
|
123
|
+
- Previous Search/Replace blocks get removed to maintain focus
|
|
124
|
+
- Instructions follow clear markdown formatting
|
|
125
|
+
- Reduces "tunnel vision" where agents fixate on minor issues
|
|
126
|
+
- Full prompt visibility through logging for debugging
|
|
127
|
+
|
|
128
|
+
### Integrated Tooling
|
|
129
|
+
|
|
130
|
+
Linting, formatting, and testing run automatically after code changes are applied. Configure your tools once and they work seamlessly in the background without requiring agent interaction.
|
|
131
|
+
|
|
132
|
+
### Controlled MCP Integration
|
|
133
|
+
|
|
134
|
+
Model Context Protocol (MCP) tools are available but tightly controlled. Manually run tools or restrict which agents can access specific capabilities.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Built With
|
|
139
|
+
|
|
140
|
+
Byte leverages modern Python tooling and AI frameworks:
|
|
141
|
+
|
|
142
|
+
- **uv** - Fast Python package management
|
|
143
|
+
- **LangChain** - AI framework for language models
|
|
144
|
+
- **LangGraph** - Graph-based agent workflows
|
|
145
|
+
- **Rich** - Beautiful terminal output
|
|
146
|
+
- **Prompt Toolkit** - Interactive command-line interfaces
|
|
147
|
+
- **Catppuccin** - Soothing pastel theme
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Inspiration
|
|
152
|
+
|
|
153
|
+
Byte draws inspiration from excellent projects in the coding agent space:
|
|
154
|
+
|
|
155
|
+
- [Aider](http://aider.chat/) - The pioneering CLI coding agent that proved the concept
|
|
156
|
+
- [Charm's Crush](https://github.com/charmbracelet/crush) - Elegant terminal agent
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
[License information to be added]
|
|
163
|
+
|
|
164
|
+
## Contributing
|
|
165
|
+
|
|
166
|
+
[Contribution guidelines to be added]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Byte
|
|
2
|
+
|
|
3
|
+
<p align="center"><img alt="Byte Logo" src="docs/images/logo.svg" /></p>
|
|
4
|
+
|
|
5
|
+
A human-in-the-loop AI coding agent that keeps you in control. Byte helps you build through natural conversation while maintaining full visibility and approval over every change.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is Byte?
|
|
10
|
+
|
|
11
|
+
Byte is a CLI coding agent designed for developers who want AI assistance without sacrificing control. Unlike autonomous agents that make multiple decisions and tool calls independently, Byte requires your approval for every decision.
|
|
12
|
+
|
|
13
|
+
**Key Features:**
|
|
14
|
+
|
|
15
|
+
- Review and confirm every change before it's applied
|
|
16
|
+
- See exactly what the agent modifies in your code
|
|
17
|
+
- Manage precisely what information the AI receives
|
|
18
|
+
- Slots into your existing development environment
|
|
19
|
+
- Structured prompts that adapt and evolve with each interaction
|
|
20
|
+
- Automatic linting, formatting, and testing without extra commands
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Design Philosophy
|
|
25
|
+
|
|
26
|
+
**Transparency First** - You see the complete prompt, not just your input. All interactions are logged for reference and debugging.
|
|
27
|
+
|
|
28
|
+
**Explicit Over Implicit** - Changes require approval. Context additions need confirmation. No surprises.
|
|
29
|
+
|
|
30
|
+
**Complementary, Not Replacement** - Byte enhances your workflow without replacing your tools or editor.
|
|
31
|
+
|
|
32
|
+
**Quality Over Quantity** - Better prompts produce better results. Byte prioritizes well-structured instructions over large context windows.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
Get started with Byte in three steps:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Install with uv
|
|
42
|
+
$ uv tool install byte
|
|
43
|
+
|
|
44
|
+
# Navigate to your project
|
|
45
|
+
$ cd /path/to/your/project
|
|
46
|
+
|
|
47
|
+
# Run Byte
|
|
48
|
+
$ byte
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
See the [Installation Guide](<[getting-started/installation.md](https://usethefork.github.io/byte/getting-started/installation/)>) for other installation methods including pip and Nix.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Why This Approach?
|
|
56
|
+
|
|
57
|
+
### Human-in-the-Loop Design
|
|
58
|
+
|
|
59
|
+
Every decision and code change requires your confirmation. If you prefer agents that work autonomously, Byte isn't for you. If you value control and transparency, you'll appreciate the deliberate confirmation flow.
|
|
60
|
+
|
|
61
|
+
### Built for Experienced Developers
|
|
62
|
+
|
|
63
|
+
Designed for experienced developers who understand good design principles. This isn't a tool where you provide a specification and it builds the entire feature. Instead, Byte excels at small, incremental changes that keep you in control. Understanding when to refactor, how to structure code, and what constitutes good design remains your responsibility.
|
|
64
|
+
|
|
65
|
+
### Search/Replace Over Tools
|
|
66
|
+
|
|
67
|
+
Instead of giving the AI arbitrary tools, explicit Search/Replace blocks show you the exact changes before they happen, making it easy to cancel or modify the proposed work.
|
|
68
|
+
|
|
69
|
+
### Workflow Preservation
|
|
70
|
+
|
|
71
|
+
Your editor stays central to development. Whether you use Vim, VS Code, or Jetbrains, Byte complements your existing workflow as something you invoke when needed.
|
|
72
|
+
|
|
73
|
+
### Context Management
|
|
74
|
+
|
|
75
|
+
You control exactly what context the LLM receives:
|
|
76
|
+
|
|
77
|
+
- Add or remove files from the active context
|
|
78
|
+
- Monitor token usage and memory consumption
|
|
79
|
+
- Prevent context overflow with targeted information
|
|
80
|
+
|
|
81
|
+
### Intelligent Prompting
|
|
82
|
+
|
|
83
|
+
Structured prompts adapt with each turn:
|
|
84
|
+
|
|
85
|
+
- Previous Search/Replace blocks get removed to maintain focus
|
|
86
|
+
- Instructions follow clear markdown formatting
|
|
87
|
+
- Reduces "tunnel vision" where agents fixate on minor issues
|
|
88
|
+
- Full prompt visibility through logging for debugging
|
|
89
|
+
|
|
90
|
+
### Integrated Tooling
|
|
91
|
+
|
|
92
|
+
Linting, formatting, and testing run automatically after code changes are applied. Configure your tools once and they work seamlessly in the background without requiring agent interaction.
|
|
93
|
+
|
|
94
|
+
### Controlled MCP Integration
|
|
95
|
+
|
|
96
|
+
Model Context Protocol (MCP) tools are available but tightly controlled. Manually run tools or restrict which agents can access specific capabilities.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Built With
|
|
101
|
+
|
|
102
|
+
Byte leverages modern Python tooling and AI frameworks:
|
|
103
|
+
|
|
104
|
+
- **uv** - Fast Python package management
|
|
105
|
+
- **LangChain** - AI framework for language models
|
|
106
|
+
- **LangGraph** - Graph-based agent workflows
|
|
107
|
+
- **Rich** - Beautiful terminal output
|
|
108
|
+
- **Prompt Toolkit** - Interactive command-line interfaces
|
|
109
|
+
- **Catppuccin** - Soothing pastel theme
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Inspiration
|
|
114
|
+
|
|
115
|
+
Byte draws inspiration from excellent projects in the coding agent space:
|
|
116
|
+
|
|
117
|
+
- [Aider](http://aider.chat/) - The pioneering CLI coding agent that proved the concept
|
|
118
|
+
- [Charm's Crush](https://github.com/charmbracelet/crush) - Elegant terminal agent
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
[License information to be added]
|
|
125
|
+
|
|
126
|
+
## Contributing
|
|
127
|
+
|
|
128
|
+
[Contribution guidelines to be added]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "byte-ai-cli"
|
|
3
|
+
version = "0.1.8"
|
|
4
|
+
description = "A human-in-the-loop AI coding agent that keeps you in control."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Environment :: Console",
|
|
9
|
+
"Intended Audience :: Developers",
|
|
10
|
+
"License :: OSI Approved :: Apache Software License",
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Programming Language :: Python :: 3.10",
|
|
13
|
+
"Programming Language :: Python :: 3.11",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Programming Language :: Python",
|
|
16
|
+
"Topic :: Software Development",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"pyperclip>=1.9.0",
|
|
20
|
+
"aiosqlite>=0.21.0",
|
|
21
|
+
"beautifulsoup4>=4.14.2",
|
|
22
|
+
"click>=8.2.1",
|
|
23
|
+
"gitpython>=3.1.45",
|
|
24
|
+
"langchain-mcp-adapters>=0.1.10",
|
|
25
|
+
"langchain[anthropic,google-genai,openai]>=0.3.27",
|
|
26
|
+
"langgraph>=0.6.7",
|
|
27
|
+
"langgraph-checkpoint-sqlite>=2.0.11",
|
|
28
|
+
"markdownify>=1.2.0",
|
|
29
|
+
"pathspec>=0.12.1",
|
|
30
|
+
"prompt-toolkit>=3.0.52",
|
|
31
|
+
"pydantic>=2.11.7",
|
|
32
|
+
"pydantic-settings>=2.10.1",
|
|
33
|
+
"pydoll-python>=2.8.2",
|
|
34
|
+
"pyperclip>=1.11.0",
|
|
35
|
+
"python-dotenv>=1.1.1",
|
|
36
|
+
"pyyaml>=6.0.2",
|
|
37
|
+
"rich>=14.1.0",
|
|
38
|
+
"watchfiles>=1.1.0",
|
|
39
|
+
"loguru>=0.7.3",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/UseTheFork/byte"
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
byte = "byte.core.cli:cli"
|
|
47
|
+
|
|
48
|
+
[tool.uv.build-backend]
|
|
49
|
+
module-name = "byte"
|
|
50
|
+
|
|
51
|
+
[dependency-groups]
|
|
52
|
+
dev = [
|
|
53
|
+
"dill>=0.4.0",
|
|
54
|
+
"grandalf>=0.8",
|
|
55
|
+
"pytest>=8.4.2",
|
|
56
|
+
"pytest-asyncio>=1.2.0",
|
|
57
|
+
"ruff>=0.12.12",
|
|
58
|
+
"tomli>=2.2.1",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
mkdocs = ["mkdocs>=1.6.1", "mkdocs-material>=9.6.21", "mkdocstrings>=0.30.1"]
|
|
62
|
+
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
target-version = "py312"
|
|
65
|
+
line-length = 120
|
|
66
|
+
|
|
67
|
+
[tool.ruff.lint]
|
|
68
|
+
select = [
|
|
69
|
+
# keep-sorted start
|
|
70
|
+
"E",
|
|
71
|
+
"F",
|
|
72
|
+
"FURB",
|
|
73
|
+
"G",
|
|
74
|
+
"I",
|
|
75
|
+
"ICN",
|
|
76
|
+
"ISC",
|
|
77
|
+
"LOG",
|
|
78
|
+
"PIE",
|
|
79
|
+
"PT",
|
|
80
|
+
"Q",
|
|
81
|
+
"RSE",
|
|
82
|
+
"RUF",
|
|
83
|
+
"T10",
|
|
84
|
+
"UP",
|
|
85
|
+
# keep-sorted end
|
|
86
|
+
]
|
|
87
|
+
ignore = [
|
|
88
|
+
# keep-sorted start
|
|
89
|
+
"E111",
|
|
90
|
+
"E114",
|
|
91
|
+
"E117",
|
|
92
|
+
"E501",
|
|
93
|
+
"E712",
|
|
94
|
+
"ISC001",
|
|
95
|
+
"PIE790",
|
|
96
|
+
"Q001",
|
|
97
|
+
"Q002",
|
|
98
|
+
"Q003",
|
|
99
|
+
"RUF005",
|
|
100
|
+
"RUF006",
|
|
101
|
+
"RUF012",
|
|
102
|
+
"UP006",
|
|
103
|
+
"UP007",
|
|
104
|
+
"UP035",
|
|
105
|
+
"UP045",
|
|
106
|
+
"W191",
|
|
107
|
+
# keep-sorted end
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.format]
|
|
111
|
+
indent-style = "tab"
|
|
112
|
+
line-ending = "lf"
|
|
113
|
+
|
|
114
|
+
[tool.ruff.lint.isort]
|
|
115
|
+
combine-as-imports = true
|
|
116
|
+
|
|
117
|
+
[tool.basedpyright]
|
|
118
|
+
include = ["src"]
|
|
119
|
+
exclude = ["**/node_modules", "**/__pycache__"]
|
|
120
|
+
pythonPlatform = "All"
|
|
121
|
+
pythonVersion = "3.12"
|
|
122
|
+
reportIgnoreCommentWithoutRule = true
|
|
123
|
+
reportRedeclaration = false
|
|
124
|
+
reportUnnecessaryTypeIgnoreComment = "warning"
|
|
125
|
+
typeCheckingMode = "basic"
|
|
126
|
+
|
|
127
|
+
executionEnvironments = [
|
|
128
|
+
{ root = "src/tests", reportPrivateUsage = false, extraPaths = [
|
|
129
|
+
"src/tests/e2e",
|
|
130
|
+
] },
|
|
131
|
+
{ root = "src" },
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[build-system]
|
|
135
|
+
requires = ["uv_build>=0.8.10,<0.9.0"]
|
|
136
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from byte.container import app
|
|
2
|
+
from byte.core.config.config import ByteConfg
|
|
3
|
+
from byte.core.event_bus import EventBus
|
|
4
|
+
from byte.core.task_manager import TaskManager
|
|
5
|
+
from byte.domain.agent.service_provider import AgentServiceProvider
|
|
6
|
+
from byte.domain.analytics.service_provider import AnalyticsProvider
|
|
7
|
+
from byte.domain.cli.service.command_registry import CommandRegistry
|
|
8
|
+
from byte.domain.cli.service.console_service import ConsoleService
|
|
9
|
+
from byte.domain.cli.service_provider import CLIServiceProvider
|
|
10
|
+
from byte.domain.development.service_provider import DevelopmentProvider
|
|
11
|
+
from byte.domain.edit_format.service_provider import EditFormatProvider
|
|
12
|
+
from byte.domain.files.service_provider import FileServiceProvider
|
|
13
|
+
from byte.domain.git.service_provider import GitServiceProvider
|
|
14
|
+
from byte.domain.knowledge.service_provider import KnowledgeServiceProvider
|
|
15
|
+
from byte.domain.lint.service_provider import LintServiceProvider
|
|
16
|
+
from byte.domain.llm.service_provider import LLMServiceProvider
|
|
17
|
+
from byte.domain.mcp.service_provider import MCPServiceProvider
|
|
18
|
+
from byte.domain.memory.service_provider import MemoryServiceProvider
|
|
19
|
+
from byte.domain.system.service_provider import SystemServiceProvider
|
|
20
|
+
from byte.domain.tools.service_provider import ToolsServiceProvider
|
|
21
|
+
from byte.domain.web.service_provider import WebServiceProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def bootstrap(config: ByteConfg):
|
|
25
|
+
"""Initialize and configure the application's dependency injection container.
|
|
26
|
+
|
|
27
|
+
Follows a two-phase initialization pattern: register all services first,
|
|
28
|
+
then boot them. This ensures all dependencies are available during the
|
|
29
|
+
boot phase when services may need to reference each other.
|
|
30
|
+
|
|
31
|
+
Returns the fully configured container ready for use.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
app.singleton(EventBus)
|
|
35
|
+
app.singleton(TaskManager)
|
|
36
|
+
|
|
37
|
+
# Make the global command registry available through dependency injection
|
|
38
|
+
app.singleton(CommandRegistry)
|
|
39
|
+
|
|
40
|
+
# Boot config as early as possible
|
|
41
|
+
app.singleton(ByteConfg, lambda: config)
|
|
42
|
+
|
|
43
|
+
# Setup console early
|
|
44
|
+
app.singleton(ConsoleService)
|
|
45
|
+
|
|
46
|
+
# Order matters: ConfigServiceProvider must be early since other services
|
|
47
|
+
# may need configuration access during their boot phase
|
|
48
|
+
|
|
49
|
+
service_providers = [
|
|
50
|
+
CLIServiceProvider(), # Console and prompt services
|
|
51
|
+
MemoryServiceProvider(), # Short-term conversation memory
|
|
52
|
+
KnowledgeServiceProvider(),
|
|
53
|
+
FileServiceProvider(), # File context management
|
|
54
|
+
ToolsServiceProvider(), # File context management
|
|
55
|
+
LLMServiceProvider(), # Language model integration
|
|
56
|
+
GitServiceProvider(), # Git repository operations
|
|
57
|
+
LintServiceProvider(), # Code linting functionality
|
|
58
|
+
AgentServiceProvider(), # Agent routing and management
|
|
59
|
+
MCPServiceProvider(),
|
|
60
|
+
AnalyticsProvider(),
|
|
61
|
+
EditFormatProvider(),
|
|
62
|
+
WebServiceProvider(),
|
|
63
|
+
SystemServiceProvider(), # Core system commands
|
|
64
|
+
DevelopmentProvider(), # Core system commands
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
# Phase 1: Register all service bindings in the container
|
|
68
|
+
# This makes services available for dependency resolution
|
|
69
|
+
for provider in service_providers:
|
|
70
|
+
await provider.register_services(app)
|
|
71
|
+
await provider.register_commands(app)
|
|
72
|
+
await provider.register(app)
|
|
73
|
+
|
|
74
|
+
# Phase 2: Boot services after all are registered
|
|
75
|
+
# This allows services to safely reference dependencies during initialization
|
|
76
|
+
for provider in service_providers:
|
|
77
|
+
await provider.boot_commands(app)
|
|
78
|
+
await provider.boot(app)
|
|
79
|
+
|
|
80
|
+
# Store service providers for shutdown
|
|
81
|
+
app._service_providers = service_providers
|
|
82
|
+
|
|
83
|
+
return app
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
async def shutdown(container):
|
|
87
|
+
"""Shutdown all service providers in reverse order."""
|
|
88
|
+
if hasattr(container, "_service_providers"):
|
|
89
|
+
# Shutdown in reverse order (opposite of boot)
|
|
90
|
+
for provider in reversed(container._service_providers):
|
|
91
|
+
await provider.shutdown(container)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Any, Callable, Dict, Optional, Type, TypeVar
|
|
3
|
+
|
|
4
|
+
from byte.core.mixins.bootable import Bootable
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Container:
|
|
10
|
+
"""Simple dependency injection container for managing service bindings.
|
|
11
|
+
|
|
12
|
+
Implements the Service Locator pattern with support for both transient
|
|
13
|
+
and singleton lifetimes. Services are resolved lazily on first access.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self._singletons: Dict[Type, Callable[[], Any]] = {}
|
|
18
|
+
self._transients: Dict[Type, Callable[[], Any]] = {}
|
|
19
|
+
self._instances: Dict[Type, Any] = {}
|
|
20
|
+
self._service_providers = []
|
|
21
|
+
|
|
22
|
+
def bind(self, service_class: Type[T], concrete: Optional[Callable[[], T]] = None) -> None:
|
|
23
|
+
"""Register a transient service binding.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
container.bind(FileService, lambda: FileService(container))
|
|
27
|
+
container.bind(FileService) # Auto-creates with container
|
|
28
|
+
"""
|
|
29
|
+
if concrete is None:
|
|
30
|
+
|
|
31
|
+
def concrete():
|
|
32
|
+
return service_class(self) # pyright: ignore[reportCallIssue]
|
|
33
|
+
|
|
34
|
+
self._transients[service_class] = concrete
|
|
35
|
+
|
|
36
|
+
def singleton(self, service_class: Type[T], concrete: Optional[Callable[[], T]] = None) -> None:
|
|
37
|
+
"""Register a singleton service binding.
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
container.singleton(FileService, lambda: FileService(container))
|
|
41
|
+
container.singleton(FileService) # Auto-creates with container
|
|
42
|
+
"""
|
|
43
|
+
if concrete is None:
|
|
44
|
+
# Auto-create factory for class
|
|
45
|
+
def concrete():
|
|
46
|
+
return service_class(self) # pyright: ignore[reportCallIssue]
|
|
47
|
+
|
|
48
|
+
self._singletons[service_class] = concrete
|
|
49
|
+
|
|
50
|
+
async def make(self, service_class: Type[T], **kwargs) -> T:
|
|
51
|
+
"""Resolve a service from the container.
|
|
52
|
+
|
|
53
|
+
Usage:
|
|
54
|
+
file_service = await container.make(FileService)
|
|
55
|
+
"""
|
|
56
|
+
# Return cached singleton instance if available
|
|
57
|
+
if service_class in self._instances:
|
|
58
|
+
return self._instances[service_class]
|
|
59
|
+
|
|
60
|
+
# Try to create from singleton bindings
|
|
61
|
+
if service_class in self._singletons:
|
|
62
|
+
factory = self._singletons[service_class]
|
|
63
|
+
instance = await self._create_instance(factory, **kwargs)
|
|
64
|
+
self._instances[service_class] = instance # Cache it
|
|
65
|
+
return instance
|
|
66
|
+
|
|
67
|
+
# Try to create from transient bindings
|
|
68
|
+
if service_class in self._transients:
|
|
69
|
+
factory = self._transients[service_class]
|
|
70
|
+
return await self._create_instance(factory, **kwargs) # Don't cache
|
|
71
|
+
|
|
72
|
+
raise ValueError(f"No binding found for {service_class.__name__}")
|
|
73
|
+
|
|
74
|
+
async def _create_instance(self, factory: Callable, **kwargs) -> Any:
|
|
75
|
+
"""Helper to create and boot instances."""
|
|
76
|
+
if asyncio.iscoroutinefunction(factory):
|
|
77
|
+
instance = await factory()
|
|
78
|
+
else:
|
|
79
|
+
instance = factory()
|
|
80
|
+
|
|
81
|
+
if isinstance(instance, Bootable):
|
|
82
|
+
await instance.ensure_booted(**kwargs)
|
|
83
|
+
|
|
84
|
+
return instance
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Global application container instance
|
|
88
|
+
# Using a global container simplifies service access across the application
|
|
89
|
+
# while maintaining the benefits of dependency injection
|
|
90
|
+
app = Container()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from contextvars import ContextVar
|
|
2
|
+
from typing import Optional, Type, TypeVar
|
|
3
|
+
|
|
4
|
+
from byte.container import Container
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T")
|
|
7
|
+
|
|
8
|
+
container_context: ContextVar[Optional["Container"]] = ContextVar("container", default=None)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_container() -> "Container":
|
|
12
|
+
"""Get the current container from context."""
|
|
13
|
+
container = container_context.get()
|
|
14
|
+
if container is None:
|
|
15
|
+
raise RuntimeError("No container available in current context")
|
|
16
|
+
return container
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def make[T](service_class: Type[T]) -> T:
|
|
20
|
+
"""Convenience method to get a service from the current container context."""
|
|
21
|
+
container = get_container()
|
|
22
|
+
return await container.make(service_class)
|