Compare commits
288 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
18dd8a7c06 | |
|
|
80e8a712ac | |
|
|
3c0319d50f | |
|
|
8d44ba0824 | |
|
|
1dc9326154 | |
|
|
c848c04ee3 | |
|
|
fee23fcc21 | |
|
|
510e1016f8 | |
|
|
64a04e2535 | |
|
|
c18c4dbd22 | |
|
|
77cfbdeca7 | |
|
|
e0aab1021b | |
|
|
5d07a7f7b8 | |
|
|
6c159d39d4 | |
|
|
cde8eee4fa | |
|
|
f1274b3164 | |
|
|
9225ec3f2a | |
|
|
bef504d756 | |
|
|
75636f0477 | |
|
|
a3dfb81840 | |
|
|
05eb50bd97 | |
|
|
46dd75a7e3 | |
|
|
e692f383c4 | |
|
|
6e5f58e18d | |
|
|
7671312435 | |
|
|
f7aaccec76 | |
|
|
f1277aadf1 | |
|
|
aaf09c5df6 | |
|
|
997c5e7ea7 | |
|
|
92faf8fc2d | |
|
|
7d85dc2b05 | |
|
|
29c9cac4f4 | |
|
|
fe3adbd241 | |
|
|
5445a5c4a9 | |
|
|
39ed523288 | |
|
|
0fe019bc9a | |
|
|
3f28ea80aa | |
|
|
0c40fa72c3 | |
|
|
07c6c2e5b5 | |
|
|
fe3984329d | |
|
|
0a46e3c92b | |
|
|
8a507f245e | |
|
|
af16879dd6 | |
|
|
f29658fee8 | |
|
|
996608e4e3 | |
|
|
262c9f7d77 | |
|
|
d5d250b215 | |
|
|
9f24c6bef9 | |
|
|
1ced6ece4c | |
|
|
a9c7f92687 | |
|
|
4685550605 | |
|
|
a2129641ae | |
|
|
9d585f38b5 | |
|
|
fa66066c07 | |
|
|
c511cefc67 | |
|
|
f08e9455b6 | |
|
|
be0b566edb | |
|
|
be415ca968 | |
|
|
715d5f483d | |
|
|
85cabe4d37 | |
|
|
80cafa9a40 | |
|
|
26b1dbe966 | |
|
|
a9656552a9 | |
|
|
b6f0f6a577 | |
|
|
77a256317a | |
|
|
fdd73f149c | |
|
|
12d27952d5 | |
|
|
826c53e01a | |
|
|
7cfbcb5a2e | |
|
|
d15d249929 | |
|
|
8d2d273c6b | |
|
|
e42f281f94 | |
|
|
376d486db8 | |
|
|
a3284c9d7e | |
|
|
ee73c85b02 | |
|
|
09ba1ee0b9 | |
|
|
c8fbd942ac | |
|
|
5c9a1e81d2 | |
|
|
376fe18b83 | |
|
|
89ee1d96ef | |
|
|
750c0d893b | |
|
|
37764c7d56 | |
|
|
ae9cf5021b | |
|
|
5d899d3d13 | |
|
|
d0985b6b84 | |
|
|
7038a61693 | |
|
|
96093e8dfc | |
|
|
b4b0fdd686 | |
|
|
4aa1b0ba93 | |
|
|
c4b2d2bb51 | |
|
|
89e4556e7b | |
|
|
4d4eb6cadb | |
|
|
8f2adc7f61 | |
|
|
f43c5e72b6 | |
|
|
416689b030 | |
|
|
909825bf1b | |
|
|
b3010bb649 | |
|
|
78983ec20b | |
|
|
a18998be0d | |
|
|
3db7cc2ca9 | |
|
|
b5e4c64042 | |
|
|
7d579f5557 | |
|
|
e81421a95a | |
|
|
c98c107ce3 | |
|
|
51fa86b5c4 | |
|
|
d8dcc8ca86 | |
|
|
a437a1e8c3 | |
|
|
4f2c36b958 | |
|
|
2899b5f848 | |
|
|
ddd0e2ae2d | |
|
|
d194868cff | |
|
|
053908448f | |
|
|
d0bf78c5f0 | |
|
|
0a143e8fff | |
|
|
eaf79fbee5 | |
|
|
fd772ee369 | |
|
|
35f91aa128 | |
|
|
ff653c7208 | |
|
|
cfb0ec148f | |
|
|
8f1e072e20 | |
|
|
2130334837 | |
|
|
d7fb269f4d | |
|
|
e64c4066a6 | |
|
|
c323098aec | |
|
|
f1a33fc1c0 | |
|
|
b9241780d0 | |
|
|
b262305592 | |
|
|
eff01b62aa | |
|
|
c1b84cd645 | |
|
|
b4d7cd30ce | |
|
|
96dbd1c4e7 | |
|
|
4d2b10c80c | |
|
|
ffc340a82f | |
|
|
4a63946df5 | |
|
|
e49cce301f | |
|
|
cf150173aa | |
|
|
66287baf0e | |
|
|
e08a8feabc | |
|
|
1643518b50 | |
|
|
58c0739cfc | |
|
|
60e4616313 | |
|
|
3607803bf5 | |
|
|
638776c8f8 | |
|
|
6e39d39b42 | |
|
|
faf9821c84 | |
|
|
089bd9b368 | |
|
|
95f9d8c2c4 | |
|
|
9e9c3ad3d2 | |
|
|
77856bfa0c | |
|
|
53406f1ddf | |
|
|
85a461e048 | |
|
|
f0e098cd82 | |
|
|
97716a941a | |
|
|
756b7bf85a | |
|
|
4ea13c6675 | |
|
|
c637807e08 | |
|
|
254a9f4d13 | |
|
|
07a5900b59 | |
|
|
0b621b6008 | |
|
|
c9f3f37ca3 | |
|
|
5bd8c76a22 | |
|
|
3e68dd3fa6 | |
|
|
60a6707107 | |
|
|
a1b268fdf4 | |
|
|
d907a0ea9c | |
|
|
47cb6b65ef | |
|
|
600bf355d9 | |
|
|
0afed55809 | |
|
|
7845f4d876 | |
|
|
e9c6aa7b4f | |
|
|
bf96ddec45 | |
|
|
a0775e3792 | |
|
|
fb030e9049 | |
|
|
5dfb41b000 | |
|
|
3d5b5850b4 | |
|
|
bee7416bf2 | |
|
|
535c870568 | |
|
|
13729f16ce | |
|
|
4859a4cdc5 | |
|
|
9cae0ef1fc | |
|
|
bd02bffc55 | |
|
|
e45cd78c7f | |
|
|
039aa8f22a | |
|
|
035544c77a | |
|
|
6562b6c332 | |
|
|
5202d2e7f3 | |
|
|
fc58aa0b77 | |
|
|
ffd1ef15d4 | |
|
|
36e4004db0 | |
|
|
dd9af78693 | |
|
|
bc9d11e6e2 | |
|
|
539af1d537 | |
|
|
bd05dee716 | |
|
|
1c95080897 | |
|
|
80e8d9134b | |
|
|
9a69bb173e | |
|
|
f88ad5bc7a | |
|
|
186904c0ca | |
|
|
d4353b1824 | |
|
|
332cbec826 | |
|
|
772ce3e049 | |
|
|
cb3504016f | |
|
|
038e7b886c | |
|
|
be2eb298a5 | |
|
|
073c68d010 | |
|
|
746649a1bb | |
|
|
935a013a4c | |
|
|
8819f463a1 | |
|
|
714d55e50a | |
|
|
7ec6535eef | |
|
|
2418506d7e | |
|
|
d41416b4d7 | |
|
|
1855cc3252 | |
|
|
14c9bdfdc7 | |
|
|
17ab6d2a50 | |
|
|
5736144d89 | |
|
|
fd1025f74c | |
|
|
c3504ee5e5 | |
|
|
cd29014282 | |
|
|
c3f32d640d | |
|
|
09bd7cbf4b | |
|
|
f89d40527d | |
|
|
23d5e267f4 | |
|
|
50d618c8f8 | |
|
|
e960a68d29 | |
|
|
429f854fb8 | |
|
|
99bbcdbc2f | |
|
|
9924c70471 | |
|
|
346e22b5cb | |
|
|
9202cf0d6d | |
|
|
9403b8c57f | |
|
|
6c85a39bbb | |
|
|
6d2b0a148d | |
|
|
a8030104fc | |
|
|
d11393c898 | |
|
|
fbc4e05d4e | |
|
|
a791e9f2d9 | |
|
|
79ca08137c | |
|
|
d6bcf44700 | |
|
|
8760e6e152 | |
|
|
1ce52774d7 | |
|
|
c89a92e4f0 | |
|
|
c83815c836 | |
|
|
9f6089d0d7 | |
|
|
4cfb377bb1 | |
|
|
6b7d2374ee | |
|
|
65b8619517 | |
|
|
4aeb52e41d | |
|
|
28d9032ca5 | |
|
|
724dbd4fda | |
|
|
e6d98737a8 | |
|
|
dbf4d954e1 | |
|
|
f05d30ff50 | |
|
|
012d95cf00 | |
|
|
840abf96f7 | |
|
|
9c76745bcc | |
|
|
94d655ce91 | |
|
|
8d1e4a96bd | |
|
|
f5de1e55b4 | |
|
|
0199f450ee | |
|
|
3f2a706ff6 | |
|
|
78793bb786 | |
|
|
8c8ae5384d | |
|
|
d3b4d9b8d9 | |
|
|
7ae4c61af6 | |
|
|
eede183110 | |
|
|
2e13b2bf4d | |
|
|
804ebd76a5 | |
|
|
f14863a06d | |
|
|
a866b38883 | |
|
|
ea44e5dd6a | |
|
|
d163a74c47 | |
|
|
2f132bdeb5 | |
|
|
495ed838ea | |
|
|
d8f1618b2b | |
|
|
860eb484c7 | |
|
|
ac9aeece2a | |
|
|
7b4359eb28 | |
|
|
c37e5b0ac1 | |
|
|
47d548180a | |
|
|
52722f6600 | |
|
|
cc93961bf3 | |
|
|
b600bd8d48 | |
|
|
6591400ad6 | |
|
|
7f85e93431 | |
|
|
04913bdaf3 | |
|
|
2c18655fb7 | |
|
|
e5593305d3 |
|
|
@ -13,4 +13,9 @@ __pycache__/
|
|||
/htmlcov
|
||||
.envrc
|
||||
appmap.log
|
||||
|
||||
*.swp
|
||||
/vsc/node_modules
|
||||
/vsc/dist
|
||||
node_modules/
|
||||
/frontend/common/dist
|
||||
/frontend/web/dist/
|
||||
|
|
|
|||
192
CHANGELOG.md
192
CHANGELOG.md
|
|
@ -5,6 +5,198 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.17.1] 2025-03-13
|
||||
|
||||
### Fixed
|
||||
- Fixed bug with `process_thinking_content` function by moving it from `agent_utils` to `ra_aid.text.processing` module
|
||||
- Fixed config parameter handling in research request functions
|
||||
- Updated development setup instructions in README to use `pip install -e ".[dev]"` instead of `pip install -r requirements-dev.txt`
|
||||
|
||||
## [0.17.0] 2025-03-12
|
||||
|
||||
### Added
|
||||
- Added support for think tags in models with the new extract_think_tag function
|
||||
- Enhanced CiaynAgent and expert tool to extract and display thinking content from <think>...</think> tags
|
||||
- Added model parameters for think tag support
|
||||
- Added comprehensive testing for think tag functionality
|
||||
- Added `--show-thoughts` flag to show thoughts of thinking models
|
||||
- Added `--show-cost` flag to display cost information during agent operations
|
||||
- Enhanced cost tracking with AnthropicCallbackHandler for monitoring token usage and costs
|
||||
- Added Session and Trajectory models to track application state and agent actions
|
||||
- Added comprehensive environment inventory system for collecting and providing system information to agents
|
||||
- Added repository implementations for Session and Trajectory models
|
||||
- Added support for reasoning assistance in research phase
|
||||
- Added new config parameters for managing cost display and reasoning assistance
|
||||
|
||||
### Changed
|
||||
- Updated langchain/langgraph deps
|
||||
- Improved trajectory tracking for better debugging and analysis
|
||||
- Enhanced prompts throughout the system for better performance
|
||||
- Improved token management with better handling of thinking tokens in Claude models
|
||||
- Updated project information inclusion in prompts
|
||||
- Reorganized agent code with better extraction of core functionality
|
||||
- Refactored anthropic token limiting for better control over token usage
|
||||
|
||||
### Fixed
|
||||
- Fixed binary file detection
|
||||
- Fixed environment inventory sorting
|
||||
- Fixed token limiter functionality
|
||||
- Various test improvements and fixes
|
||||
|
||||
## [0.16.1] 2025-03-07
|
||||
|
||||
### Changed
|
||||
- Replaced thread-local storage with contextvars in agent_context.py for better context isolation
|
||||
- Improved React agent execution with LangGraph's interrupt mechanism
|
||||
- Enhanced _run_agent_stream function to properly handle agent state and continuation
|
||||
|
||||
### Fixed
|
||||
- Fixed tests to work with the new implementation
|
||||
|
||||
## [0.16.0] 2025-03-07
|
||||
|
||||
### Added
|
||||
- Database-backed memory system with SQLite (.ra-aid/pk.db)
|
||||
- Repository pattern for memory access (KeyFactRepository, KeySnippetRepository, ResearchNoteRepository)
|
||||
- Memory garbage collection with configurable thresholds
|
||||
- "--wipe-project-memory" flag to reset memory
|
||||
- Memory statistics in status panel
|
||||
- Propagation depth control for agent_should_exit
|
||||
- Fixed string parameter for ripgrep tool
|
||||
- Support for Claude 3.7 Sonnet thinking tokens in expert tool
|
||||
|
||||
### Changed
|
||||
- Enhanced file logging with support for .ra-aid/logs/
|
||||
- Improved CiaynAgent with better tool validation and execution
|
||||
- Memory-related prompt improvements
|
||||
|
||||
### Fixed
|
||||
- Various bug fixes in tool execution
|
||||
- Test improvements for memory system
|
||||
|
||||
## [0.15.2] - 2025-02-27
|
||||
|
||||
### Added
|
||||
- Added agent_should_exit context functionality with propagation to parent contexts
|
||||
- Improved agent crash detection with non-propagating crash state
|
||||
- Enhanced ripgrep tool with better context support
|
||||
- Improved agent context inheritance
|
||||
- Added comprehensive test coverage for exit and crash handling
|
||||
|
||||
## [0.15.1] - 2025-02-27
|
||||
|
||||
### Fixed
|
||||
- Improved chat prompt to prevent endless loop behavior with sonnet 3.7.
|
||||
|
||||
## [0.15.0] - 2025-02-27
|
||||
|
||||
### Added
|
||||
- Added database infrastructure with models, connections, and migrations
|
||||
- Added agent context system for improved context management
|
||||
- Added aider-free mode with command line option to disable aider-related functionality
|
||||
- Added database-related dependencies
|
||||
|
||||
### Changed
|
||||
- Improved file editing tools with enhanced functionality
|
||||
- Enhanced agent implementation tools with modified return values and logic
|
||||
- Improved agent tool prompts for better clarity and effectiveness
|
||||
- Fixed langgraph prebuilt dependency
|
||||
|
||||
### Fixed
|
||||
- Fixed project state detection logic with added tests
|
||||
|
||||
## [0.14.9] - 2025-02-25
|
||||
|
||||
### Added
|
||||
- Added binary file detection and filtering to prevent binary files from being added to related files
|
||||
- Added python-magic dependency for improved binary file detection
|
||||
- Added support for "thinking" budget parameter for Claude 3.7 Sonnet
|
||||
|
||||
### Changed
|
||||
- Updated dependencies:
|
||||
- langchain-anthropic from 0.3.7 to 0.3.8
|
||||
- langchain-google-genai from 2.0.10 to 2.0.11
|
||||
- Improved shell command tool description to recommend keeping commands under 300 words
|
||||
- Enhanced binary file filtering to include detailed reporting of skipped files
|
||||
- Updated test assertions to be more flexible with parameter checking
|
||||
|
||||
## [0.14.8] - 2025-02-25
|
||||
|
||||
### Changed
|
||||
- Improved programmer.py tool prompts for better clarity on related files visibility
|
||||
- Enhanced programmer tool to remind users to call emit_related_files on any new files created
|
||||
- Updated README.md to use media queries for showing different logos based on color scheme preference
|
||||
|
||||
|
||||
## [0.14.7] - 2025-02-25
|
||||
|
||||
### Added
|
||||
- Windows compatibility improvements
|
||||
- Add error handling for Windows-specific modules
|
||||
- Add Windows-specific tests for compatibility
|
||||
|
||||
### Changed
|
||||
- Improve cross-platform support in interactive.py
|
||||
- WebUI improvements
|
||||
- Improve message display
|
||||
- Add syntax highlighting
|
||||
- Add animations
|
||||
- Expert tool prompt improvements
|
||||
|
||||
### Fixed
|
||||
- WebUI improvements
|
||||
- Fix WebSocket communication
|
||||
- Interactive command handling improvements
|
||||
- Fix interactive history capture
|
||||
- Fix command capture bugs
|
||||
- Multiple fixes for interactive command execution on both Linux and Windows
|
||||
- Enhance error handling for interactive processes
|
||||
|
||||
## [0.14.6] - 2025-02-25
|
||||
|
||||
### Added
|
||||
- Added `--no-git` flag to aider commands to prevent git operations
|
||||
|
||||
### Changed
|
||||
- Updated aider-chat dependency from 0.75 to 0.75.1
|
||||
- Improved prompts for better tool effectiveness
|
||||
- Enhanced emit_key_snippet documentation to focus on upcoming work relevance
|
||||
|
||||
## [0.14.5] - 2025-02-24
|
||||
|
||||
### Changed
|
||||
- Optimized prompts
|
||||
|
||||
## [0.14.4] - 2025-02-24
|
||||
|
||||
### Changed
|
||||
- Updated aider-chat dependency from 0.74.2 to 0.75
|
||||
- Improved tool calling performance by minimizing tool return values
|
||||
- Replaced emit_key_snippets with emit_key_snippet for simpler code snippet management
|
||||
- Simplified return values for multiple tools to improve tool calling accuracy
|
||||
- Updated tool prompts to remove unnecessary context cleanup references
|
||||
- Reorganized order of tools in read-only tools list
|
||||
|
||||
### Fixed
|
||||
- Fixed tests to align with updated tool return values
|
||||
- Updated test assertions to match new simplified tool outputs
|
||||
|
||||
## [0.14.3] - 2025-02-24
|
||||
|
||||
### Added
|
||||
- Added support for Claude 3.7 Sonnet model
|
||||
- Added version display in startup configuration panel
|
||||
|
||||
### Changed
|
||||
- Updated language library dependencies (langgraph, langchain-core, langchain, langchain-openai, langchain-google-genai)
|
||||
- Changed default Anthropic model from Claude 3.5 Sonnet to Claude 3.7 Sonnet
|
||||
|
||||
### Fixed
|
||||
- Fixed f-string syntax error in write_file.py
|
||||
- Fixed bug where model selection on Anthropic was always using default instead of respecting user selection
|
||||
- Fixed Anthropic key error message to reference the correct variable
|
||||
- Added test for user-specified Anthropic model selection
|
||||
|
||||
## [0.14.2] - 2025-02-19
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
include LICENSE
|
||||
include README.md
|
||||
include CHANGELOG.md
|
||||
recursive-include ra_aid/webui/static *
|
||||
recursive-include ra_aid/server/static *
|
||||
|
|
|
|||
95
README.md
95
README.md
|
|
@ -1,4 +1,8 @@
|
|||
<img src="assets/RA-black-bg.png" alt="RA.Aid - Develop software autonomously." style="margin-bottom: 20px;">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="assets/logo-white-transparent.gif">
|
||||
<source media="(prefers-color-scheme: light)" srcset="assets/logo-black-transparent.png">
|
||||
<img src="assets/logo-black-transparent.png" alt="RA.Aid - Develop software autonomously." style="margin-bottom: 20px;">
|
||||
</picture>
|
||||
|
||||
[](https://www.python.org)
|
||||
[](LICENSE)
|
||||
|
|
@ -6,7 +10,7 @@
|
|||
|
||||
**Develop software autonomously.**
|
||||
|
||||
RA.Aid (pronounced "raid") helps you develop software autonomously. It was made by putting `aider` (https://aider.chat/) in a LangChain ReAct agent loop. This unique combination allows developers to leverage `aider`'s code editing capabilities while benefiting from LangChain's agent-based task execution framework. The tool provides an intelligent assistant that can help with research, planning, and implementation of multi-step development tasks.
|
||||
RA.Aid (pronounced "raid") helps you develop software autonomously. It is a standalone coding agent built on LangGraph's agent-based task execution framework. The tool provides an intelligent assistant that can help with research, planning, and implementation of multi-step development tasks. RA.Aid can optionally integrate with `aider` (https://aider.chat/) via the `--use-aider` flag to leverage its specialized code editing capabilities.
|
||||
|
||||
The result is **near-fully-autonomous software development**.
|
||||
|
||||
|
|
@ -25,6 +29,8 @@ Key sections:
|
|||
- [Recommended Configuration](https://docs.ra-aid.ai/quickstart/recommended)
|
||||
- [Open Models Setup](https://docs.ra-aid.ai/quickstart/open-models)
|
||||
- [Usage Examples](https://docs.ra-aid.ai/category/usage)
|
||||
- [Logging System](https://docs.ra-aid.ai/configuration/logging)
|
||||
- [Memory Management](https://docs.ra-aid.ai/configuration/memory-management)
|
||||
- [Contributing Guide](https://docs.ra-aid.ai/contributing)
|
||||
- [Getting Help](https://docs.ra-aid.ai/getting-help)
|
||||
|
||||
|
|
@ -97,6 +103,31 @@ What sets RA.Aid apart is its ability to handle complex programming tasks that e
|
|||
|
||||
## Installation
|
||||
|
||||
### Windows Installation
|
||||
1. Install Python 3.8 or higher from [python.org](https://www.python.org/downloads/)
|
||||
2. Install required system dependencies:
|
||||
```powershell
|
||||
# Install Chocolatey if not already installed (run in admin PowerShell)
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
|
||||
# Install ripgrep using Chocolatey
|
||||
choco install ripgrep
|
||||
```
|
||||
3. Install RA.Aid:
|
||||
```powershell
|
||||
pip install ra-aid
|
||||
```
|
||||
4. Install Windows-specific dependencies:
|
||||
```powershell
|
||||
pip install pywin32
|
||||
```
|
||||
5. Set up your API keys in a `.env` file:
|
||||
```env
|
||||
ANTHROPIC_API_KEY=your_anthropic_key
|
||||
OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
|
||||
### Unix/Linux Installation
|
||||
RA.Aid can be installed directly using pip:
|
||||
|
||||
```bash
|
||||
|
|
@ -129,7 +160,7 @@ export GEMINI_API_KEY=your_api_key_here
|
|||
export TAVILY_API_KEY=your_api_key_here
|
||||
```
|
||||
|
||||
Note: The programmer tool (aider) will automatically select its model based on your available API keys:
|
||||
Note: When using the `--use-aider` flag, the programmer tool (aider) will automatically select its model based on your available API keys:
|
||||
- If ANTHROPIC_API_KEY is set, it will use Claude models
|
||||
- If only OPENAI_API_KEY is set, it will use OpenAI models
|
||||
- You can set multiple API keys to enable different features
|
||||
|
|
@ -153,11 +184,14 @@ ra-aid -m "Your task or query here"
|
|||
# Research-only mode (no implementation)
|
||||
ra-aid -m "Explain the authentication flow" --research-only
|
||||
|
||||
# Enable verbose logging for detailed execution information
|
||||
ra-aid -m "Add new feature" --verbose
|
||||
# File logging with console warnings (default mode)
|
||||
ra-aid -m "Add new feature" --log-mode file
|
||||
|
||||
# Console-only logging with detailed output
|
||||
ra-aid -m "Add new feature" --log-mode console --log-level debug
|
||||
```
|
||||
|
||||
More information is available in our [Usage Examples](https://docs.ra-aid.ai/category/usage).
|
||||
More information is available in our [Usage Examples](https://docs.ra-aid.ai/category/usage), [Logging System](https://docs.ra-aid.ai/configuration/logging), and [Memory Management](https://docs.ra-aid.ai/configuration/memory-management) documentation.
|
||||
|
||||
### Command Line Options
|
||||
|
||||
|
|
@ -165,6 +199,7 @@ More information is available in our [Usage Examples](https://docs.ra-aid.ai/cat
|
|||
- `--research-only`: Only perform research without implementation
|
||||
- `--provider`: The LLM provider to use (choices: anthropic, openai, openrouter, openai-compatible, gemini)
|
||||
- `--model`: The model name to use (required for non-Anthropic providers)
|
||||
- `--use-aider`: Enable aider integration for code editing. When enabled, RA.Aid uses aider's specialized code editing capabilities instead of its own native file modification tools. This option is useful when you need aider's specific editing features or prefer its approach to code modifications. This feature is optional and disabled by default.
|
||||
- `--research-provider`: Provider to use specifically for research tasks (falls back to --provider if not specified)
|
||||
- `--research-model`: Model to use specifically for research tasks (falls back to --model if not specified)
|
||||
- `--planner-provider`: Provider to use specifically for planning tasks (falls back to --provider if not specified)
|
||||
|
|
@ -174,9 +209,15 @@ More information is available in our [Usage Examples](https://docs.ra-aid.ai/cat
|
|||
- `--expert-model`: The model name to use for expert knowledge queries (required for non-OpenAI providers)
|
||||
- `--hil, -H`: Enable human-in-the-loop mode for interactive assistance during task execution
|
||||
- `--chat`: Enable chat mode with direct human interaction (implies --hil)
|
||||
- `--verbose`: Enable verbose logging output
|
||||
- `--log-mode`: Logging mode (choices: file, console)
|
||||
- `file` (default): Logs to both file and console (only warnings and errors to console)
|
||||
- `console`: Logs to console only at the specified log level with no file logging
|
||||
- `--log-level`: Set specific logging level (debug, info, warning, error, critical)
|
||||
- With `--log-mode=file`: Controls the file logging level (console still shows only warnings+)
|
||||
- With `--log-mode=console`: Controls the console logging level directly
|
||||
- Default: warning
|
||||
- `--experimental-fallback-handler`: Enable experimental fallback handler to attempt to fix too calls when the same tool fails 3 times consecutively. (OPENAI_API_KEY recommended as openai has the top 5 tool calling models.) See `ra_aid/tool_leaderboard.py` for more info.
|
||||
- `--pretty-logger`: Enables panel markdown formatted logger messages for debugging purposes.
|
||||
- `--pretty-logger`: Enables colored panel-style formatted logging output for better readability.
|
||||
- `--temperature`: LLM temperature (0.0-2.0) to control randomness in responses
|
||||
- `--disable-limit-tokens`: Disable token limiting for Anthropic Claude react agents
|
||||
- `--recursion-limit`: Maximum recursion depth for agent operations (default: 100)
|
||||
|
|
@ -185,9 +226,9 @@ More information is available in our [Usage Examples](https://docs.ra-aid.ai/cat
|
|||
- `--max-test-cmd-retries`: Maximum number of test command retry attempts (default: 3)
|
||||
- `--test-cmd-timeout`: Timeout in seconds for test command execution (default: 300)
|
||||
- `--version`: Show program version number and exit
|
||||
- `--webui`: Launch the web interface (alpha feature)
|
||||
- `--webui-host`: Host to listen on for web interface (default: 0.0.0.0) (alpha feature)
|
||||
- `--webui-port`: Port to listen on for web interface (default: 8080) (alpha feature)
|
||||
- `--server`: Launch the server with web interface (alpha feature)
|
||||
- `--server-host`: Host to listen on for server (default: 0.0.0.0) (alpha feature)
|
||||
- `--server-port`: Port to listen on for server (default: 1818) (alpha feature)
|
||||
|
||||
### Example Tasks
|
||||
|
||||
|
|
@ -264,30 +305,30 @@ Make sure to set your TAVILY_API_KEY environment variable to enable this feature
|
|||
|
||||
Enable with `--chat` to transform ra-aid into an interactive assistant that guides you through research and implementation tasks. Have a natural conversation about what you want to build, explore options together, and dispatch work - all while maintaining context of your discussion. Perfect for when you want to think through problems collaboratively rather than just executing commands.
|
||||
|
||||
### Web Interface
|
||||
### Server with Web Interface
|
||||
|
||||
RA.Aid includes a modern web interface that provides:
|
||||
RA.Aid includes a modern server with web interface that provides:
|
||||
- Beautiful dark-themed chat interface
|
||||
- Real-time streaming of command output
|
||||
- Request history with quick resubmission
|
||||
- Responsive design that works on all devices
|
||||
|
||||
To launch the web interface:
|
||||
To launch the server with web interface:
|
||||
|
||||
```bash
|
||||
# Start with default settings (0.0.0.0:8080)
|
||||
ra-aid --webui
|
||||
# Start with default settings (0.0.0.0:1818)
|
||||
ra-aid --server
|
||||
|
||||
# Specify custom host and port
|
||||
ra-aid --webui --webui-host 127.0.0.1 --webui-port 3000
|
||||
ra-aid --server --server-host 127.0.0.1 --server-port 3000
|
||||
```
|
||||
|
||||
Command line options for web interface:
|
||||
- `--webui`: Launch the web interface
|
||||
- `--webui-host`: Host to listen on (default: 0.0.0.0)
|
||||
- `--webui-port`: Port to listen on (default: 8080)
|
||||
Command line options for server with web interface:
|
||||
- `--server`: Launch the server with web interface
|
||||
- `--server-host`: Host to listen on (default: 0.0.0.0)
|
||||
- `--server-port`: Port to listen on (default: 1818)
|
||||
|
||||
After starting the server, open your web browser to the displayed URL (e.g., http://localhost:8080). The interface provides:
|
||||
After starting the server, open your web browser to the displayed URL (e.g., http://localhost:1818). The interface provides:
|
||||
- Left sidebar showing request history
|
||||
- Main chat area with real-time output
|
||||
- Input box for typing requests
|
||||
|
|
@ -324,9 +365,9 @@ ra-aid -m "Update all deprecated API calls" --cowboy-mode
|
|||
|
||||
### Model Configuration
|
||||
|
||||
RA.Aid supports multiple AI providers and models. The default model is Anthropic's Claude 3 Sonnet (`claude-3-5-sonnet-20241022`).
|
||||
RA.Aid supports multiple AI providers and models. The default model is Anthropic's Claude 3 Sonnet (`claude-3-7-sonnet-20250219`).
|
||||
|
||||
The programmer tool (aider) automatically selects its model based on your available API keys. It will use Claude models if ANTHROPIC_API_KEY is set, or fall back to OpenAI models if only OPENAI_API_KEY is available.
|
||||
When using the `--use-aider` flag, the programmer tool (aider) automatically selects its model based on your available API keys. It will use Claude models if ANTHROPIC_API_KEY is set, or fall back to OpenAI models if only OPENAI_API_KEY is available.
|
||||
|
||||
Note: The expert tool can be configured to use different providers (OpenAI, Anthropic, OpenRouter, Gemini) using the --expert-provider flag along with the corresponding EXPERT_*API_KEY environment variables. Each provider requires its own API key set through the appropriate environment variable.
|
||||
|
||||
|
|
@ -372,7 +413,7 @@ export GEMINI_API_KEY=your_api_key_here
|
|||
|
||||
1. **Using Anthropic (Default)**
|
||||
```bash
|
||||
# Uses default model (claude-3-5-sonnet-20241022)
|
||||
# Uses default model (claude-3-7-sonnet-20250219)
|
||||
ra-aid -m "Your task"
|
||||
|
||||
# Or explicitly specify:
|
||||
|
|
@ -438,7 +479,7 @@ Note: For `AIDER_FLAGS`, you can specify flags with or without the leading `--`.
|
|||
**Important Notes:**
|
||||
- Performance varies between models. The default Claude 3 Sonnet model currently provides the best and most reliable results.
|
||||
- Model configuration is done via command line arguments: `--provider` and `--model`
|
||||
- The `--model` argument is required for all providers except Anthropic (which defaults to `claude-3-5-sonnet-20241022`)
|
||||
- The `--model` argument is required for all providers except Anthropic (which defaults to `claude-3-7-sonnet-20250219`)
|
||||
|
||||
More information is available in our [Open Models Setup](https://docs.ra-aid.ai/quickstart/open-models) guide.
|
||||
|
||||
|
|
@ -500,7 +541,7 @@ source venv/bin/activate # On Windows use `venv\Scripts\activate`
|
|||
|
||||
3. Install development dependencies:
|
||||
```bash
|
||||
pip install -r requirements-dev.txt
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
4. Run tests:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "frontend/common/tailwind.config.js",
|
||||
"css": "frontend/common/src/styles/global.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@ra-aid/common/components",
|
||||
"utils": "@ra-aid/common/utils"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"label": "Configuration",
|
||||
"position": 3,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Configure RA.Aid for optimal performance and behavior."
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
# Logging System
|
||||
|
||||
RA.Aid includes a powerful and flexible logging system that helps you troubleshoot issues and monitor the tool's operation. This document explains how to configure and use the logging features effectively.
|
||||
|
||||
## Overview
|
||||
|
||||
The logging system in RA.Aid provides:
|
||||
|
||||
- Configurable logging modes for different use cases
|
||||
- Multiple log levels for controlling verbosity
|
||||
- File logging with rotation and backup capabilities
|
||||
- Pretty console logging with formatted display
|
||||
- Comprehensive log messages capturing agent activity
|
||||
|
||||
## Command Line Options
|
||||
|
||||
RA.Aid provides the following command line options to control logging behavior:
|
||||
|
||||
### Log Mode
|
||||
|
||||
The `--log-mode` option determines where logs are directed:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --log-mode file
|
||||
```
|
||||
|
||||
Available modes:
|
||||
|
||||
- `file` (default): Logs are written to both file and console
|
||||
- Console shows only warnings and errors
|
||||
- File contains all logs at the specified log level
|
||||
- `console`: Logs are only shown in the console at the specified log level
|
||||
- No log files are created
|
||||
|
||||
### Log Level
|
||||
|
||||
The `--log-level` option controls the verbosity of logging:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --log-level debug
|
||||
```
|
||||
|
||||
Available levels (case-insensitive):
|
||||
|
||||
- `debug`: Most verbose, includes detailed debugging information
|
||||
- `info`: General information about operations
|
||||
- `warning` (default): Potential issues that might need attention
|
||||
- `error`: Error conditions that prevent normal operation
|
||||
- `critical`: Critical errors that may cause the application to terminate
|
||||
|
||||
The log level affects different outputs depending on the log mode:
|
||||
- With `--log-mode=file`: Controls the file logging level, while console still shows only warnings and errors
|
||||
- With `--log-mode=console`: Controls the console logging level directly
|
||||
|
||||
### Pretty Logger
|
||||
|
||||
The `--pretty-logger` option enables formatted panel-style logging output:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --pretty-logger
|
||||
```
|
||||
|
||||
When enabled, log messages appear in colored panels with titles indicating the log level:
|
||||
- 🔥 CRITICAL: Bold red panels for critical errors
|
||||
- ❌ ERROR: Red panels for errors
|
||||
- ⚠️ WARNING: Yellow panels for warnings
|
||||
- ℹ️ INFO: Green panels for informational messages
|
||||
- 🐞 DEBUG: Blue panels for debug messages
|
||||
|
||||
## Log Files
|
||||
|
||||
When `--log-mode=file` is used, RA.Aid creates and maintains log files with the following characteristics:
|
||||
|
||||
### Location
|
||||
|
||||
Log files are stored in the `.ra-aid/logs/` directory in your current working directory:
|
||||
|
||||
```
|
||||
.ra-aid/logs/ra_aid_YYYYMMDD_HHMMSS.log
|
||||
```
|
||||
|
||||
RA.Aid automatically creates this directory if it doesn't exist.
|
||||
|
||||
### Naming Convention
|
||||
|
||||
Log files follow a timestamp-based naming pattern:
|
||||
|
||||
```
|
||||
ra_aid_YYYYMMDD_HHMMSS.log
|
||||
```
|
||||
|
||||
Where:
|
||||
- `YYYYMMDD`: Year, month, and day when the log file was created
|
||||
- `HHMMSS`: Hour, minute, and second when the log file was created
|
||||
|
||||
Example: `ra_aid_20250301_143027.log`
|
||||
|
||||
### Log Rotation
|
||||
|
||||
RA.Aid uses automatic log rotation to manage log file size and prevent excessive disk usage:
|
||||
|
||||
- Maximum file size: 5 MB
|
||||
- Maximum backup files: 100
|
||||
|
||||
When a log file reaches 5 MB, it is renamed with a numeric suffix (e.g., `.1`, `.2`), and a new log file is created. Up to 100 backup files are maintained.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage (Default)
|
||||
|
||||
Use the default file logging mode with warnings and errors:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature"
|
||||
```
|
||||
|
||||
### Detailed File Logging
|
||||
|
||||
Log everything including debug messages to file (console still shows only warnings+):
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --log-level debug
|
||||
```
|
||||
|
||||
### Console-Only Debugging
|
||||
|
||||
Get detailed debug logs in the console without creating log files:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --log-mode console --log-level debug
|
||||
```
|
||||
|
||||
### Informational Console Logging
|
||||
|
||||
Get informational console output without debug details:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --log-mode console --log-level info
|
||||
```
|
||||
|
||||
### Pretty Logging Output
|
||||
|
||||
Use formatted panel-style logging for better readability:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add new feature" --pretty-logger
|
||||
```
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
- For troubleshooting issues, start with `--log-mode console --log-level debug`
|
||||
- Examine log files in `.ra-aid/logs/` for historical issues
|
||||
- Use `--pretty-logger` when working with complex tasks for better log clarity
|
||||
- For production use, the default settings (`--log-mode file --log-level warning`) provide a good balance of information without excessive output
|
||||
|
||||
## Log Message Format
|
||||
|
||||
Standard log messages follow this format:
|
||||
|
||||
```
|
||||
YYYY-MM-DD HH:MM:SS,MS - logger_name - LEVEL - Message text
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
2025-03-01 14:30:27,123 - ra_aid.agent_utils - WARNING - Command execution timeout after 60 seconds
|
||||
```
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
# Memory Management
|
||||
|
||||
## Introduction
|
||||
RA.Aid's memory system enables the agent to persist knowledge across sessions, creating a more efficient and coherent experience. The memory stores key facts, code snippets, and research notes about your project, allowing RA.Aid to build on previous work and avoid redundant operations.
|
||||
|
||||
This persistent memory gives RA.Aid the ability to:
|
||||
- Remember important project facts and architectural decisions
|
||||
- Store relevant code snippets with their file locations
|
||||
- Preserve research findings and technical notes
|
||||
- Build contextual understanding of your project over time
|
||||
|
||||
## Database Architecture
|
||||
RA.Aid's memory is stored in a SQLite database file located in a hidden `.ra-aid` directory within your current working directory. The specific file path is:
|
||||
|
||||
```
|
||||
.ra-aid/pk.db
|
||||
```
|
||||
|
||||
This database implements several key tables:
|
||||
- `KeyFact`: Stores important facts about your project
|
||||
- `KeySnippet`: Preserves code snippets with their file paths and line numbers
|
||||
- `ResearchNote`: Contains detailed research findings
|
||||
- `HumanInput`: Tracks user inputs to provide context for memory items
|
||||
|
||||
All memory items have timestamps (created_at, updated_at) that help with relevance tracking and garbage collection.
|
||||
|
||||
The memory system uses thread-local state via Python's contextvars to ensure thread safety when multiple components access the database simultaneously.
|
||||
|
||||
## Memory Repositories and Garbage Collection
|
||||
RA.Aid implements the repository pattern for database access, with specialized repositories for each memory type:
|
||||
- `KeyFactRepository`
|
||||
- `KeySnippetRepository`
|
||||
- `ResearchNoteRepository`
|
||||
|
||||
Each repository provides methods to add, query, and delete items while abstracting the underlying database implementation.
|
||||
|
||||
To prevent uncontrolled growth of the memory database, RA.Aid implements automatic garbage collection that triggers when specific thresholds are exceeded:
|
||||
- Facts: > 50 items
|
||||
- Snippets: > 35 items
|
||||
- Notes: > 30 items
|
||||
|
||||
When garbage collection activates, specialized agents analyze all stored items, considering factors like:
|
||||
- Relevance to the current task
|
||||
- Age of the memory items
|
||||
- Relationship to other items
|
||||
- Overall importance
|
||||
|
||||
Memory items associated with the current human input are protected from garbage collection to preserve context for the active task.
|
||||
|
||||
## CLI Commands and Configuration
|
||||
RA.Aid provides a CLI flag to completely reset the memory database:
|
||||
|
||||
```bash
|
||||
ra-aid --wipe-project-memory [other arguments]
|
||||
```
|
||||
|
||||
This flag deletes the entire `.ra-aid/pk.db` database file, giving you a fresh start with no stored memory.
|
||||
|
||||
The memory statistics are displayed in the status panel when you start RA.Aid, showing:
|
||||
- The number of facts, snippets, and notes currently stored
|
||||
- A reminder about the `--wipe-project-memory` flag when memory items exist
|
||||
|
||||
### When to Wipe Memory
|
||||
You might want to wipe project memory in these situations:
|
||||
|
||||
1. **Major Codebase Changes**: When your project has undergone significant refactoring or structural changes, making the stored memory items obsolete.
|
||||
|
||||
2. **Fresh Start**: When beginning a new phase of development and you want to clear out irrelevant historical context.
|
||||
|
||||
3. **Incorrect Information**: If the agent has stored incorrect or outdated information that's affecting its performance.
|
||||
|
||||
4. **Troubleshooting**: When unexpected behavior might be related to the stored memory items.
|
||||
|
||||
## Troubleshooting
|
||||
Common memory-related issues and their solutions:
|
||||
|
||||
### Issue: Agent recalling outdated information
|
||||
**Solution**: Use `--wipe-project-memory` to reset the memory database, especially after major code changes.
|
||||
|
||||
### Issue: Database lockup or corruption
|
||||
**Solution**:
|
||||
1. Ensure RA.Aid has properly shut down before starting a new session
|
||||
2. If issues persist, use `--wipe-project-memory` to recreate the database
|
||||
3. Check the logs in `.ra-aid/logs/` for specific errors
|
||||
|
||||
### Issue: Memory items seem irrelevant
|
||||
**Solution**:
|
||||
- Let the automatic garbage collection work by continuing to use RA.Aid
|
||||
- For immediate reset, use `--wipe-project-memory`
|
||||
|
||||
### Issue: Missing .ra-aid directory
|
||||
**Solution**: The directory is automatically created when you run RA.Aid. If it's missing, simply run RA.Aid again.
|
||||
|
||||
## Examples / Use Cases
|
||||
|
||||
### Example 1: Wiping memory after major refactoring
|
||||
|
||||
```bash
|
||||
# After refactoring your project structure
|
||||
ra-aid --wipe-project-memory -m "Update the authentication system"
|
||||
```
|
||||
|
||||
### Example 2: Starting a new development phase
|
||||
|
||||
```bash
|
||||
# Before starting work on a new major feature
|
||||
ra-aid --wipe-project-memory -m "Implement payment processing system"
|
||||
```
|
||||
|
||||
### Example 3: Checking memory status without wiping
|
||||
|
||||
```bash
|
||||
# Check the memory statistics in the status panel
|
||||
ra-aid -m "Show me the project structure"
|
||||
# Look for the 💾 Memory: X facts, Y snippets, Z notes line
|
||||
```
|
||||
|
||||
### Example 4: Using memory during ongoing development
|
||||
|
||||
When working on a complex feature over multiple sessions, memory allows RA.Aid to:
|
||||
1. Remember architectural decisions from previous sessions
|
||||
2. Recall the context of partially implemented features
|
||||
3. Build on previous research without repeating the same queries
|
||||
4. Maintain awareness of project constraints and requirements
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
# Reasoning Assistance
|
||||
|
||||
## Overview
|
||||
|
||||
Reasoning Assistance is a feature in RA.Aid that helps weaker models make better decisions about tool usage and task planning. It leverages a stronger model (typically your expert model) to provide strategic guidance to the main agent model at the beginning of each agent stage.
|
||||
|
||||
This feature is particularly useful when working with less capable models that may struggle with complex reasoning, tool selection, or planning. By providing expert guidance upfront, these models can perform more effectively and produce better results.
|
||||
|
||||
## How It Works
|
||||
|
||||
When reasoning assistance is enabled, RA.Aid performs the following steps at the beginning of each agent stage (research, planning, implementation):
|
||||
|
||||
1. Makes a one-off call to the expert model with a specialized prompt that includes:
|
||||
- A description of the current task and stage
|
||||
- The complete list of available tools
|
||||
- Instructions to provide strategic guidance on approaching the task
|
||||
|
||||
2. Incorporates the expert model's response into the main agent's prompt.
|
||||
|
||||
3. The main agent then proceeds with execution, guided by the expert's recommendations on which tools to use and how to approach the task
|
||||
|
||||
## Configuration
|
||||
|
||||
### Command Line Flags
|
||||
|
||||
You can enable or disable reasoning assistance using these command-line flags:
|
||||
|
||||
```bash
|
||||
# Enable reasoning assistance
|
||||
ra-aid -m "Your task description" --reasoning-assistance
|
||||
|
||||
# Disable reasoning assistance (overrides model defaults)
|
||||
ra-aid -m "Your task description" --no-reasoning-assistance
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Using Reasoning Assistance with Weaker Models
|
||||
|
||||
```bash
|
||||
# Use qwen-qwq-32b as the expert model to provide guidance
|
||||
ra-aid --model qwen-32b-coder-instruct --expert-model qwen-qwq-32b --reasoning-assistance -m "Create a simple web server in Python"
|
||||
```
|
||||
|
||||
### Disabling Reasoning Assistance for Strong Models
|
||||
|
||||
Reasoning assistance has different defaults depending on which model is used. If you would like to explicitly disable reasoning assistance, use the `--no-reasoning-assistance` flag.
|
||||
|
||||
```bash
|
||||
# Use Claude 3 Opus without reasoning assistance
|
||||
ra-aid -m "Create a simple web server in Python" --model claude-3-opus-20240229 --no-reasoning-assistance
|
||||
```
|
||||
|
||||
## Benefits and Use Cases
|
||||
|
||||
Reasoning assistance provides several advantages:
|
||||
|
||||
1. **Better Tool Selection**: Helps models choose the right tools for specific tasks
|
||||
2. **Improved Planning**: Provides strategic guidance on how to approach complex problems
|
||||
3. **Reduced Errors**: Decreases the likelihood of tool misuse or inefficient approaches
|
||||
4. **Model Flexibility**: Allows using weaker models more effectively by augmenting their reasoning capabilities
|
||||
5. **Consistency**: Ensures more consistent behavior across different models
|
||||
|
||||
Common use cases include:
|
||||
|
||||
- Working with open-source models that have less robust tool use capabilities
|
||||
- Tackling complex tasks that require careful planning and tool sequencing
|
||||
- Ensuring consistent behavior when switching between different models
|
||||
|
||||
## Best Practices
|
||||
|
||||
For optimal results with reasoning assistance:
|
||||
|
||||
1. **Use Strong Expert Models**: The quality of reasoning assistance depends on the expert model's capabilities. Use the strongest model available for the expert role.
|
||||
|
||||
2. **Enable for Weaker Models**: Enable reasoning assistance by default for models known to struggle with tool selection or complex reasoning.
|
||||
|
||||
3. **Disable for Strong Models**: Models like Claude 3 Opus or GPT-4 typically don't need reasoning assistance and might perform better without it.
|
||||
|
||||
4. **Custom Tasks**: For highly specialized or unusual tasks, manually enabling reasoning assistance can be beneficial even for stronger models.
|
||||
|
||||
5. **Review Generated Guidance**: If debugging issues, examine the expert guidance provided to understand how it's influencing the agent's behavior.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
| Issue | Possible Solution |
|
||||
|-------|-------------------|
|
||||
| Reasoning assistance seems to make no difference | Verify both `--reasoning-assistance` flag is set and check the logs to confirm the expert model is being called |
|
||||
| Expert model provides irrelevant or incorrect agent guidance | Try using a stronger expert model with `--expert-model` flag |
|
||||
| Agent ignores expert guidance | Some models may not correctly follow the guidance format; try a different agent model |
|
||||
| Slow performance | Reasoning assistance requires an additional model call at the start of each stage; disable it for simpler tasks if speed is critical |
|
||||
| Conflicting approach with custom instructions | If you're providing specific instructions that conflict with reasoning assistance, use `--no-reasoning-assistance` |
|
||||
|
||||
If problems persist, check if the expert model and agent model are compatible, and consider adjusting the temperature setting to control randomness in both models.
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
# Thinking Models
|
||||
|
||||
RA.Aid supports models that can reveal their internal reasoning process, providing greater transparency into how they arrive at their responses. This feature, called "thinking models," helps users better understand the model's decision-making and logic.
|
||||
|
||||
## Overview
|
||||
|
||||
Thinking models allow you to see the model's internal reasoning process separately from its final response. This offers several benefits:
|
||||
|
||||
- **Transparency**: Understand how the model interprets your instructions and reasons through problems
|
||||
- **Debugging**: Identify where a model's reasoning might go astray
|
||||
- **Learning**: Gain insights into the model's approach to problem-solving
|
||||
- **Trust**: Build greater confidence in the model's outputs by seeing its thought process
|
||||
|
||||
RA.Aid extracts and displays thinking content in special "💭 Thoughts" panels, keeping the main response clean while still providing access to the reasoning behind it.
|
||||
|
||||
## How Thinking Models Work in RA.Aid
|
||||
|
||||
RA.Aid supports two different methods for implementing thinking models:
|
||||
|
||||
### 1. Explicit Think Tags
|
||||
|
||||
Some models, like `qwen-qwq-32b`, use explicit XML-style thinking tags to delineate their reasoning process:
|
||||
|
||||
```
|
||||
<think>
|
||||
First, I need to understand what this code does.
|
||||
The function seems to be parsing a configuration file...
|
||||
</think>
|
||||
|
||||
The function parse_config() has an issue with its error handling...
|
||||
```
|
||||
|
||||
RA.Aid extracts the content between these `<think>...</think>` tags and displays it separately from the main response.
|
||||
|
||||
### 2. Native Thinking Mode
|
||||
|
||||
More advanced models, like Claude 3.7 Sonnet, have native thinking capabilities built in at the API level. When RA.Aid uses these models, it sends special configuration parameters in the API request:
|
||||
|
||||
```python
|
||||
{"thinking": {"type": "enabled", "budget_tokens": 12000}}
|
||||
```
|
||||
|
||||
These models return structured responses with separate thinking and response content, which RA.Aid processes and displays accordingly.
|
||||
|
||||
## Configuration and Setup
|
||||
|
||||
### Enabling Thinking Models
|
||||
|
||||
To enable the display of thinking content, use the `--show-thoughts` CLI flag when running RA.Aid:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Add error handling to the database module" --show-thoughts
|
||||
```
|
||||
|
||||
When this flag is enabled, RA.Aid will display thinking content in separate panels whenever it's available from the model.
|
||||
|
||||
### Supported Models
|
||||
|
||||
Currently, the following models support thinking mode in RA.Aid:
|
||||
|
||||
| Model | Provider | Type |
|
||||
|-------|----------|------|
|
||||
| qwen-qwq-32b | openai-compatible | Explicit think tags |
|
||||
| claude-3-7-sonnet-20250219 | anthropic | Native thinking mode |
|
||||
|
||||
Each model's support is configured in the `models_params.py` file using the appropriate parameter.
|
||||
|
||||
## Examples and Usage
|
||||
|
||||
### Using a Model with Explicit Think Tags
|
||||
|
||||
When using the `qwen-qwq-32b` model with the `--show-thoughts` flag:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Refactor the error handling logic" --provider openai-compatible --model qwen-qwq-32b --show-thoughts
|
||||
```
|
||||
|
||||
The model might include explicit think tags in its response:
|
||||
|
||||
```
|
||||
<think>
|
||||
Let me analyze the existing error handling logic:
|
||||
1. Current approach uses try/except blocks scattered throughout
|
||||
2. Error messages are inconsistent
|
||||
3. There's no central logging mechanism
|
||||
I should suggest a unified error handling approach with proper logging.
|
||||
</think>
|
||||
|
||||
I recommend refactoring the error handling logic by implementing a centralized error handler...
|
||||
```
|
||||
|
||||
RA.Aid will extract this thinking content and display it in a separate panel titled "💭 Thoughts", while showing only the actual response in the main output.
|
||||
|
||||
### Using a Model with Native Thinking
|
||||
|
||||
When using Claude 3.7 Sonnet with the `--show-thoughts` flag:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Debug the database connection issue" --provider anthropic --model claude-3-7-sonnet-20250219 --show-thoughts
|
||||
```
|
||||
|
||||
RA.Aid configures the model to use its native thinking mode, and then processes the structured response to show thinking content separately.
|
||||
|
||||
### Without the --show-thoughts Flag
|
||||
|
||||
If you run RA.Aid without the `--show-thoughts` flag, the thinking content is still extracted from the model responses, but it won't be displayed in the console. This gives you a cleaner output focused only on the model's final responses.
|
||||
|
||||
## Troubleshooting and Best Practices
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Thinking content not appearing
|
||||
|
||||
If you're not seeing thinking content despite using the `--show-thoughts` flag:
|
||||
|
||||
- Ensure you're using a model that supports thinking (qwen-qwq-32b or claude-3-7-sonnet-20250219)
|
||||
- Verify that the model is properly configured in your environment
|
||||
- Check that the model is actually including thinking content in its responses (not all prompts will generate thinking)
|
||||
|
||||
#### Excessive or irrelevant thinking
|
||||
|
||||
If the thinking content is too verbose or irrelevant:
|
||||
|
||||
- Try to formulate more specific and concise prompts
|
||||
- Consider using a different model if the thinking style doesn't meet your needs
|
||||
|
||||
### Best Practices
|
||||
|
||||
For the most effective use of thinking models:
|
||||
|
||||
1. **Use selectively**: Enable `--show-thoughts` when you need to understand the model's reasoning process, but consider disabling it for routine tasks to keep output concise.
|
||||
|
||||
2. **Choose the right model**: Different models have different thinking styles. Claude models tend to provide more structured and methodical reasoning, while other models might have different approaches.
|
||||
|
||||
3. **Ask questions that benefit from reasoning**: Complex problem-solving, debugging, and analysis tasks benefit most from seeing the model's thought process.
|
||||
|
||||
4. **Compare thinking with output**: Use the thinking content to evaluate the quality of the model's reasoning and identify potential flaws in its approach.
|
||||
|
||||
5. **Provide clear instructions**: When the model's thinking seems off-track, provide clearer instructions in your next prompt to guide its reasoning process.
|
||||
|
||||
|
|
@ -1,5 +1,23 @@
|
|||
# Getting Help
|
||||
|
||||
## Troubleshooting Common Issues
|
||||
|
||||
Before seeking external help, check the following:
|
||||
|
||||
### Check the Logs
|
||||
|
||||
RA.Aid maintains detailed logs that can help diagnose many common issues. By default, logs are stored in the `.ra-aid/logs/` directory in your working directory.
|
||||
|
||||
1. Check the most recent log file in `.ra-aid/logs/` directory
|
||||
2. Look for ERROR or WARNING level messages that might indicate what went wrong
|
||||
3. For more detailed logging options, see the [Logging documentation](/configuration/logging)
|
||||
|
||||
### Common Problems
|
||||
|
||||
- **Error connecting to API**: Verify your API key is set correctly
|
||||
- **Command not found**: Ensure RA.Aid is installed properly and in your PATH
|
||||
- **Script execution failures**: Check that required dependencies are installed
|
||||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
If you encounter any issues or have ideas for improvements, please file them on our [GitHub Issues page](https://github.com/ai-christianson/RA.Aid/issues).
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ slug: /
|
|||
|
||||
# Welcome to RA.Aid
|
||||
|
||||
RA.Aid (pronounced "raid") is your AI-powered development companion that helps you build software autonomously. Whether you're working on new features, refactoring code, or researching solutions, RA.Aid makes development faster and more efficient.
|
||||
RA.Aid (pronounced "raid") is your AI-powered development companion that helps you build software autonomously. As a standalone coding agent built on LangChain's agent-based task execution framework, RA.Aid can handle research, planning, and implementation of your development tasks. Whether you're working on new features, refactoring code, or researching solutions, RA.Aid makes development faster and more efficient.
|
||||
|
||||
## Why RA.Aid?
|
||||
|
||||
|
|
@ -45,6 +45,8 @@ ra-aid -m "Add input validation to the login form"
|
|||
- **Interactive Mode**: Get help when you need it through natural conversation
|
||||
- **Multiple AI Providers**: Support for various AI models to suit your needs
|
||||
- **Git Integration**: Works seamlessly with your version control
|
||||
- **Standalone Code Agent**: Built-in code modification capabilities by default
|
||||
- **Optional Aider Integration**: Use the `--use-aider` flag to leverage aider's specialized code editing abilities
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,36 @@ ra-aid -m "Your task" --provider openai-compatible --model your-model-name
|
|||
- Supports temperature control
|
||||
- Compatible with most OpenAI-style APIs
|
||||
</TabItem>
|
||||
<TabItem value="gemini" label="Google Gemini">
|
||||
|
||||
### Google Gemini Models
|
||||
|
||||
Google's Gemini models offer powerful multimodal capabilities with extensive code generation support.
|
||||
|
||||
```bash
|
||||
# Environment setup
|
||||
export GEMINI_API_KEY=your_api_key_here
|
||||
|
||||
# Basic usage
|
||||
ra-aid -m "Your task" --provider gemini --model gemini-1.5-pro-latest
|
||||
|
||||
# With temperature control
|
||||
ra-aid -m "Your task" --provider gemini --model gemini-1.5-flash-latest --temperature 0.5
|
||||
```
|
||||
|
||||
**Available Models:**
|
||||
- `gemini-pro`: Original Gemini Pro model
|
||||
- `gemini-1.5-flash-latest`: Latest Gemini 1.5 Flash model (fast responses)
|
||||
- `gemini-1.5-pro-latest`: Latest Gemini 1.5 Pro model (strong reasoning)
|
||||
- `gemini-1.5-flash`: Gemini 1.5 Flash release
|
||||
- `gemini-1.5-pro`: Gemini 1.5 Pro release
|
||||
- `gemini-1.0-pro`: Original Gemini 1.0 Pro model
|
||||
|
||||
**Configuration Notes:**
|
||||
- All Gemini models support a 128,000 token context window
|
||||
- Temperature control is supported for creative vs. deterministic responses
|
||||
- Obtain your API key from [AI Studio](https://aistudio.google.com/app/apikey)
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Advanced Configuration
|
||||
|
|
@ -130,6 +160,10 @@ ra-aid -m "Your task" --expert-provider deepseek --expert-model deepseek-reasone
|
|||
# OpenRouter expert
|
||||
export EXPERT_OPENROUTER_API_KEY=your_key
|
||||
ra-aid -m "Your task" --expert-provider openrouter --expert-model mistralai/mistral-large-2411
|
||||
|
||||
# Gemini expert
|
||||
export EXPERT_GEMINI_API_KEY=your_key
|
||||
ra-aid -m "Your task" --expert-provider gemini --expert-model gemini-2.0-flash-thinking-exp-1219
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
@ -172,6 +206,7 @@ Complete list of supported environment variables:
|
|||
| `GEMINI_API_KEY` | Gemini | API access |
|
||||
| `EXPERT_OPENROUTER_API_KEY` | OpenRouter | Expert tool |
|
||||
| `EXPERT_DEEPSEEK_API_KEY` | DeepSeek | Expert tool |
|
||||
| `EXPERT_GEMINI_API_KEY` | Gemini | Expert tool |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
|||
|
|
@ -54,3 +54,23 @@ Or run with a single command:
|
|||
```bash
|
||||
ra-aid -m "Help me understand this code"
|
||||
```
|
||||
|
||||
If you prefer to use aider's specialized code editing capabilities instead of RA.Aid's built-in file modification tools:
|
||||
|
||||
```bash
|
||||
ra-aid -m "Implement this feature" --use-aider
|
||||
```
|
||||
|
||||
You can control logging verbosity and location using the `--log-mode` and `--log-level` options:
|
||||
|
||||
```bash
|
||||
# Log to file (with only warnings to console)
|
||||
ra-aid -m "Your task" --log-mode file --log-level debug
|
||||
|
||||
# Log everything to console
|
||||
ra-aid -m "Your task" --log-mode console --log-level info
|
||||
```
|
||||
|
||||
For more detailed logging configuration, see the [Logging documentation](../configuration/logging.md).
|
||||
|
||||
For information on RA.Aid's memory management and how to reset memory when needed, see the [Memory Management documentation](../configuration/memory-management.md).
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"label": "Usage",
|
||||
"position": 3,
|
||||
"position": 4,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Learn how to use RA.Aid effectively in different scenarios."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import type * as Preset from '@docusaurus/preset-classic';
|
|||
const config: Config = {
|
||||
title: 'RA-Aid Documentation',
|
||||
favicon: 'img/favicon.ico',
|
||||
url: 'https://ra-aid.0.dev',
|
||||
url: 'https://docs.ra-aid.ai',
|
||||
baseUrl: '/',
|
||||
|
||||
onDuplicateRoutes: 'ignore',
|
||||
|
|
@ -17,9 +17,7 @@ const config: Config = {
|
|||
locales: ['en'],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
'@docusaurus/plugin-vercel-analytics'
|
||||
],
|
||||
plugins: [],
|
||||
|
||||
presets: [
|
||||
[
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.7.0",
|
||||
"@docusaurus/plugin-vercel-analytics": "^3.7.0",
|
||||
"@docusaurus/preset-classic": "3.7.0",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
|
|
@ -3530,66 +3529,6 @@
|
|||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@docusaurus/plugin-vercel-analytics": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-vercel-analytics/-/plugin-vercel-analytics-3.7.0.tgz",
|
||||
"integrity": "sha512-zEOsqNI3oj4WRO9Dbzsar9fctwAl60PZJqhu14X5W3z5zT/E1TFKrHW/oJHU/a1r5o9K2cFsSNdDn2tyuaFJoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.7.0",
|
||||
"@docusaurus/logger": "3.7.0",
|
||||
"@docusaurus/types": "3.7.0",
|
||||
"@docusaurus/utils": "3.7.0",
|
||||
"@docusaurus/utils-validation": "3.7.0",
|
||||
"@vercel/analytics": "^1.1.1",
|
||||
"tslib": "^2.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@docusaurus/plugin-vercel-analytics/node_modules/@vercel/analytics": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.5.0.tgz",
|
||||
"integrity": "sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==",
|
||||
"license": "MPL-2.0",
|
||||
"peerDependencies": {
|
||||
"@remix-run/react": "^2",
|
||||
"@sveltejs/kit": "^1 || ^2",
|
||||
"next": ">= 13",
|
||||
"react": "^18 || ^19 || ^19.0.0-rc",
|
||||
"svelte": ">= 4",
|
||||
"vue": "^3",
|
||||
"vue-router": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@remix-run/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@sveltejs/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"next": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"svelte": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
},
|
||||
"vue-router": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@docusaurus/preset-classic": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.7.0.tgz",
|
||||
|
|
|
|||
|
|
@ -4,19 +4,20 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"start": "node scripts/version.js && docusaurus start",
|
||||
"generate-version": "node scripts/version.js",
|
||||
"build": "npm run generate-version && docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"typecheck": "tsc"
|
||||
"typecheck": "tsc",
|
||||
"version-json": "node scripts/version.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.7.0",
|
||||
"@docusaurus/plugin-vercel-analytics": "^3.7.0",
|
||||
"@docusaurus/preset-classic": "3.7.0",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
|
|
@ -45,4 +46,4 @@
|
|||
"engines": {
|
||||
"node": ">=18.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Docusaurus Scripts
|
||||
|
||||
This directory contains utility scripts for the Docusaurus documentation site.
|
||||
|
||||
## version.js
|
||||
|
||||
This script reads the version from `../../ra_aid/__version__.py` and creates a `version.json` file in the Docusaurus `static/` directory, which will be included in the built site.
|
||||
|
||||
### Usage
|
||||
|
||||
The script is automatically run as part of the build and start processes via npm scripts defined in `package.json`, but can also be run manually:
|
||||
|
||||
```bash
|
||||
# From docs directory
|
||||
npm run version-json
|
||||
|
||||
# Or directly
|
||||
node scripts/version.js
|
||||
```
|
||||
|
||||
### Output
|
||||
|
||||
The script creates a `static/version.json` file with the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "x.y.z"
|
||||
}
|
||||
```
|
||||
|
||||
This file will be available at `/version.json` in the built site, allowing client-side version checks.
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to read version from ra_aid/__version__.py and create version.json
|
||||
* in the Docusaurus static directory.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Paths
|
||||
const versionFilePath = path.resolve(__dirname, '../../ra_aid/__version__.py');
|
||||
const outputPath = path.resolve(__dirname, '../static/version.json');
|
||||
|
||||
/**
|
||||
* Extract version string from the __version__.py file
|
||||
* @param {string} content - The file content
|
||||
* @returns {string|null} - Extracted version or null if not found
|
||||
*/
|
||||
function extractVersion(content) {
|
||||
const regex = /__version__\s*=\s*["']([^"']+)["']/;
|
||||
const match = content.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
// Main function to create version.json
|
||||
function createVersionJson() {
|
||||
try {
|
||||
// Read version file
|
||||
console.log(`Reading version from ${versionFilePath}...`);
|
||||
const versionFileContent = fs.readFileSync(versionFilePath, 'utf8');
|
||||
|
||||
// Extract version
|
||||
const version = extractVersion(versionFileContent);
|
||||
if (!version) {
|
||||
console.error('Failed to extract version from file');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Extracted version: ${version}`);
|
||||
|
||||
// Create version JSON
|
||||
const versionJson = JSON.stringify({ version }, null, 2);
|
||||
|
||||
// Ensure static directory exists
|
||||
const staticDir = path.dirname(outputPath);
|
||||
if (!fs.existsSync(staticDir)) {
|
||||
console.log(`Creating directory: ${staticDir}`);
|
||||
fs.mkdirSync(staticDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Write JSON file
|
||||
fs.writeFileSync(outputPath, versionJson);
|
||||
console.log(`Version JSON written to ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating version.json: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the main function
|
||||
createVersionJson();
|
||||
|
|
@ -0,0 +1 @@
|
|||
version.json
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import * as React from "react";
|
||||
import { type VariantProps } from "class-variance-authority";
|
||||
declare const buttonVariants: (props?: ({
|
||||
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
||||
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
||||
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|
||||
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
||||
export { Button, buttonVariants };
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { cn } from "../../utils";
|
||||
const buttonVariants = cva("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", {
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
});
|
||||
const Button = React.forwardRef((_a, ref) => {
|
||||
var { className, variant, size, asChild = false } = _a, props = __rest(_a, ["className", "variant", "size", "asChild"]);
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (React.createElement(Comp, Object.assign({ className: cn(buttonVariants({ variant, size, className })), ref: ref }, props)));
|
||||
});
|
||||
Button.displayName = "Button";
|
||||
export { Button, buttonVariants };
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import * as React from "react";
|
||||
declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
||||
declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
||||
declare const CardTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
|
||||
declare const CardDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
||||
declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
||||
declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import * as React from "react";
|
||||
import { cn } from "../../utils";
|
||||
const Card = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("div", Object.assign({ ref: ref, className: cn("rounded-xl border bg-card text-card-foreground shadow", className) }, props)));
|
||||
});
|
||||
Card.displayName = "Card";
|
||||
const CardHeader = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("div", Object.assign({ ref: ref, className: cn("flex flex-col space-y-1.5 p-6", className) }, props)));
|
||||
});
|
||||
CardHeader.displayName = "CardHeader";
|
||||
const CardTitle = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("h3", Object.assign({ ref: ref, className: cn("font-semibold leading-none tracking-tight", className) }, props)));
|
||||
});
|
||||
CardTitle.displayName = "CardTitle";
|
||||
const CardDescription = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("p", Object.assign({ ref: ref, className: cn("text-sm text-muted-foreground", className) }, props)));
|
||||
});
|
||||
CardDescription.displayName = "CardDescription";
|
||||
const CardContent = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("div", Object.assign({ ref: ref, className: cn("p-6 pt-0", className) }, props)));
|
||||
});
|
||||
CardContent.displayName = "CardContent";
|
||||
const CardFooter = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement("div", Object.assign({ ref: ref, className: cn("flex items-center p-6 pt-0", className) }, props)));
|
||||
});
|
||||
CardFooter.displayName = "CardFooter";
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export * from './button';
|
||||
export * from './card';
|
||||
export * from './collapsible';
|
||||
export * from './floating-action-button';
|
||||
export * from './input';
|
||||
export * from './layout';
|
||||
export * from './sheet';
|
||||
export * from './switch';
|
||||
export * from './scroll-area';
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export * from './button';
|
||||
export * from './card';
|
||||
export * from './collapsible';
|
||||
export * from './floating-action-button';
|
||||
export * from './input';
|
||||
export * from './layout';
|
||||
export * from './sheet';
|
||||
export * from './switch';
|
||||
export * from './scroll-area';
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import * as React from "react";
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
}
|
||||
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
||||
export { Input };
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import * as React from "react";
|
||||
import { cn } from "../../utils";
|
||||
const Input = React.forwardRef((_a, ref) => {
|
||||
var { className, type } = _a, props = __rest(_a, ["className", "type"]);
|
||||
return (React.createElement("input", Object.assign({ type: type, className: cn("flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", className), ref: ref }, props)));
|
||||
});
|
||||
Input.displayName = "Input";
|
||||
export { Input };
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import * as React from "react";
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||
declare const Switch: React.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
||||
export { Switch };
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import * as React from "react";
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||
import { cn } from "../../utils";
|
||||
const Switch = React.forwardRef((_a, ref) => {
|
||||
var { className } = _a, props = __rest(_a, ["className"]);
|
||||
return (React.createElement(SwitchPrimitives.Root, Object.assign({ className: cn("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input", className) }, props, { ref: ref }),
|
||||
React.createElement(SwitchPrimitives.Thumb, { className: cn("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0") })));
|
||||
});
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName;
|
||||
export { Switch };
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import './styles/global.css';
|
||||
export * from './utils/types';
|
||||
export * from './utils';
|
||||
export * from './components/ui';
|
||||
export * from './components/TimelineStep';
|
||||
export * from './components/TimelineFeed';
|
||||
export * from './components/SessionDrawer';
|
||||
export * from './components/SessionSidebar';
|
||||
export * from './components/DefaultAgentScreen';
|
||||
export declare const hello: () => void;
|
||||
export { getSampleAgentSteps, getSampleAgentSessions } from './utils/sample-data';
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Entry point for @ra-aid/common package
|
||||
import './styles/global.css';
|
||||
// Export types first to avoid circular references
|
||||
export * from './utils/types';
|
||||
// Export utility functions
|
||||
export * from './utils';
|
||||
// Export UI components
|
||||
export * from './components/ui';
|
||||
// Export timeline components
|
||||
export * from './components/TimelineStep';
|
||||
export * from './components/TimelineFeed';
|
||||
// Export session navigation components
|
||||
export * from './components/SessionDrawer';
|
||||
export * from './components/SessionSidebar';
|
||||
// Export main screens
|
||||
export * from './components/DefaultAgentScreen';
|
||||
// Export the hello function (temporary example)
|
||||
export const hello = () => {
|
||||
console.log("Hello from @ra-aid/common");
|
||||
};
|
||||
// Directly export sample data functions
|
||||
export { getSampleAgentSteps, getSampleAgentSessions } from './utils/sample-data';
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
import { type ClassValue } from "clsx";
|
||||
/**
|
||||
* Merges class names with Tailwind CSS classes
|
||||
* Combines clsx for conditional logic and tailwind-merge for handling conflicting tailwind classes
|
||||
*/
|
||||
export declare function cn(...inputs: ClassValue[]): string;
|
||||
export * from './utils';
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
/**
|
||||
* Merges class names with Tailwind CSS classes
|
||||
* Combines clsx for conditional logic and tailwind-merge for handling conflicting tailwind classes
|
||||
*/
|
||||
export function cn(...inputs) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
// Re-export everything from utils directory
|
||||
export * from './utils';
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "@ra-aid/common",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "tsc && postcss src/styles/global.css -o dist/styles/global.css",
|
||||
"dev": "tsc --watch",
|
||||
"watch:css": "postcss src/styles/global.css -o dist/styles/global.css --watch",
|
||||
"watch": "concurrently \"npm run dev\" \"npm run watch:css\"",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-collapsible": "^1.1.3",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.0.0",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"lucide-react": "^0.363.0",
|
||||
"tailwind-merge": "^2.2.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.64",
|
||||
"@types/react-dom": "^18.2.21",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"concurrently": "^8.2.2",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-cli": "^10.1.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.0.0",
|
||||
"react-dom": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -0,0 +1,258 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { PanelLeft } from 'lucide-react';
|
||||
import {
|
||||
Button,
|
||||
Layout
|
||||
} from './ui';
|
||||
import { SessionDrawer } from './SessionDrawer';
|
||||
import { SessionList } from './SessionList';
|
||||
import { TimelineFeed } from './TimelineFeed';
|
||||
import { getSampleAgentSessions, getSampleAgentSteps } from '../utils/sample-data';
|
||||
import logoBlack from '../assets/logo-black-transparent.png';
|
||||
import logoWhite from '../assets/logo-white-transparent.gif';
|
||||
|
||||
/**
|
||||
* DefaultAgentScreen component
|
||||
*
|
||||
* Main application screen for displaying agent sessions and their steps.
|
||||
* Handles state management, responsive design, and UI interactions.
|
||||
*/
|
||||
export const DefaultAgentScreen: React.FC = () => {
|
||||
// State for drawer open/close
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
|
||||
// State for selected session
|
||||
const [selectedSessionId, setSelectedSessionId] = useState<string | null>(null);
|
||||
|
||||
// State for theme (dark is default)
|
||||
const [isDarkTheme, setIsDarkTheme] = useState(true);
|
||||
|
||||
// Get sample data
|
||||
const sessions = getSampleAgentSessions();
|
||||
const allSteps = getSampleAgentSteps();
|
||||
|
||||
// Set up theme on component mount
|
||||
useEffect(() => {
|
||||
const isDark = setupTheme();
|
||||
setIsDarkTheme(isDark);
|
||||
}, []);
|
||||
|
||||
// Set initial selected session if none selected
|
||||
useEffect(() => {
|
||||
if (!selectedSessionId && sessions.length > 0) {
|
||||
setSelectedSessionId(sessions[0].id);
|
||||
}
|
||||
}, [sessions, selectedSessionId]);
|
||||
|
||||
// Close drawer when window resizes to desktop width
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
// Check if we're at desktop size (corresponds to md: breakpoint in Tailwind)
|
||||
if (window.innerWidth >= 768 && isDrawerOpen) {
|
||||
setIsDrawerOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// Clean up event listener on component unmount
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, [isDrawerOpen]);
|
||||
|
||||
// Filter steps for selected session
|
||||
const selectedSessionSteps = selectedSessionId
|
||||
? allSteps.filter(step => sessions.find(s => s.id === selectedSessionId)?.steps.some(s => s.id === step.id))
|
||||
: [];
|
||||
|
||||
// Handle session selection
|
||||
const handleSessionSelect = (sessionId: string) => {
|
||||
setSelectedSessionId(sessionId);
|
||||
setIsDrawerOpen(false); // Close drawer on selection (mobile)
|
||||
};
|
||||
|
||||
// Toggle theme function
|
||||
const toggleTheme = () => {
|
||||
const newIsDark = !isDarkTheme;
|
||||
setIsDarkTheme(newIsDark);
|
||||
|
||||
// Update document element class
|
||||
if (newIsDark) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
// Save to localStorage
|
||||
localStorage.setItem('theme', newIsDark ? 'dark' : 'light');
|
||||
};
|
||||
|
||||
// Render header content
|
||||
const headerContent = (
|
||||
<div className="w-full flex items-center justify-between h-full px-4">
|
||||
<div className="flex-initial">
|
||||
{/* Use the appropriate logo based on theme */}
|
||||
<img
|
||||
src={isDarkTheme ? logoWhite : logoBlack}
|
||||
alt="RA.Aid Logo"
|
||||
className="h-8"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-initial ml-auto">
|
||||
{/* Theme toggle button */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={toggleTheme}
|
||||
aria-label={isDarkTheme ? "Switch to light mode" : "Switch to dark mode"}
|
||||
>
|
||||
{isDarkTheme ? (
|
||||
// Sun icon for light mode toggle
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="5" />
|
||||
<line x1="12" y1="1" x2="12" y2="3" />
|
||||
<line x1="12" y1="21" x2="12" y2="23" />
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
||||
<line x1="1" y1="12" x2="3" y2="12" />
|
||||
<line x1="21" y1="12" x2="23" y2="12" />
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||
</svg>
|
||||
) : (
|
||||
// Moon icon for dark mode toggle
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||
</svg>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Sidebar content with sessions list
|
||||
const sidebarContent = (
|
||||
<div className="h-full flex flex-col px-4 py-3">
|
||||
<SessionList
|
||||
sessions={sessions}
|
||||
onSelectSession={handleSessionSelect}
|
||||
currentSessionId={selectedSessionId || undefined}
|
||||
className="flex-1 pr-1 -mr-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Render drawer
|
||||
const drawerContent = (
|
||||
<SessionDrawer
|
||||
sessions={sessions}
|
||||
currentSessionId={selectedSessionId || undefined}
|
||||
onSelectSession={handleSessionSelect}
|
||||
isOpen={isDrawerOpen}
|
||||
onClose={() => setIsDrawerOpen(false)}
|
||||
/>
|
||||
);
|
||||
|
||||
// Render main content
|
||||
const mainContent = (
|
||||
selectedSessionId ? (
|
||||
<>
|
||||
<h2 className="text-xl font-semibold mb-4">
|
||||
Session: {sessions.find(s => s.id === selectedSessionId)?.name || 'Unknown'}
|
||||
</h2>
|
||||
<TimelineFeed
|
||||
steps={selectedSessionSteps}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-muted-foreground">Select a session to view details</p>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
// Floating action button component that uses Portal to render at document body level
|
||||
const FloatingActionButton = ({ onClick }: { onClick: () => void }) => {
|
||||
// Only render the portal on the client side, not during SSR
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
return () => setMounted(false);
|
||||
}, []);
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
variant="default"
|
||||
size="icon"
|
||||
onClick={onClick}
|
||||
aria-label="Toggle sessions panel"
|
||||
className="h-14 w-14 rounded-full shadow-xl bg-zinc-800 hover:bg-zinc-700 text-zinc-100 flex items-center justify-center border-2 border-zinc-700 dark:border-zinc-600"
|
||||
>
|
||||
<PanelLeft className="h-6 w-6" />
|
||||
</Button>
|
||||
);
|
||||
|
||||
const container = (
|
||||
<div className="fixed bottom-6 right-6 z-[9999] md:hidden" style={{ pointerEvents: 'auto' }}>
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
|
||||
// Return null during SSR, or the portal on the client
|
||||
return mounted ? createPortal(container, document.body) : null;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout
|
||||
header={headerContent}
|
||||
sidebar={sidebarContent}
|
||||
drawer={drawerContent}
|
||||
>
|
||||
{mainContent}
|
||||
</Layout>
|
||||
<FloatingActionButton onClick={() => setIsDrawerOpen(true)} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// Helper function for theme setup
|
||||
const setupTheme = () => {
|
||||
// Check if theme preference is stored in localStorage
|
||||
const storedTheme = localStorage.getItem('theme');
|
||||
|
||||
// Default to dark mode unless explicitly set to light
|
||||
const isDark = storedTheme ? storedTheme === 'dark' : true;
|
||||
|
||||
// Apply theme to document
|
||||
if (isDark) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
return isDark;
|
||||
};
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetClose
|
||||
} from './ui/sheet';
|
||||
import { AgentSession } from '../utils/types';
|
||||
import { getSampleAgentSessions } from '../utils/sample-data';
|
||||
import { SessionList } from './SessionList';
|
||||
|
||||
interface SessionDrawerProps {
|
||||
onSelectSession?: (sessionId: string) => void;
|
||||
currentSessionId?: string;
|
||||
sessions?: AgentSession[];
|
||||
isOpen?: boolean;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const SessionDrawer: React.FC<SessionDrawerProps> = ({
|
||||
onSelectSession,
|
||||
currentSessionId,
|
||||
sessions = getSampleAgentSessions(),
|
||||
isOpen = false,
|
||||
onClose
|
||||
}) => {
|
||||
return (
|
||||
<Sheet open={isOpen} onOpenChange={onClose}>
|
||||
<SheetContent
|
||||
side="left"
|
||||
className="w-full sm:max-w-md border-r border-border p-4"
|
||||
>
|
||||
<SheetHeader className="px-2">
|
||||
<SheetTitle>Sessions</SheetTitle>
|
||||
</SheetHeader>
|
||||
<SessionList
|
||||
sessions={sessions}
|
||||
currentSessionId={currentSessionId}
|
||||
onSelectSession={onSelectSession}
|
||||
className="h-[calc(100vh-9rem)] mt-4"
|
||||
wrapperComponent={SheetClose}
|
||||
/>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import React from 'react';
|
||||
import { ScrollArea } from './ui/scroll-area';
|
||||
import { AgentSession } from '../utils/types';
|
||||
import { getSampleAgentSessions } from '../utils/sample-data';
|
||||
|
||||
interface SessionListProps {
|
||||
onSelectSession?: (sessionId: string) => void;
|
||||
currentSessionId?: string;
|
||||
sessions?: AgentSession[];
|
||||
className?: string;
|
||||
wrapperComponent?: React.ElementType;
|
||||
closeAction?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const SessionList: React.FC<SessionListProps> = ({
|
||||
onSelectSession,
|
||||
currentSessionId,
|
||||
sessions = getSampleAgentSessions(),
|
||||
className = '',
|
||||
wrapperComponent: WrapperComponent = 'button',
|
||||
closeAction
|
||||
}) => {
|
||||
// Get status color
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return 'bg-blue-500';
|
||||
case 'completed':
|
||||
return 'bg-green-500';
|
||||
case 'error':
|
||||
return 'bg-red-500';
|
||||
default:
|
||||
return 'bg-gray-500';
|
||||
}
|
||||
};
|
||||
|
||||
// Format timestamp
|
||||
const formatDate = (date: Date) => {
|
||||
return date.toLocaleDateString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollArea className={className}>
|
||||
<div className="space-y-1.5 pt-1.5 pb-2">
|
||||
{sessions.map((session) => {
|
||||
const buttonContent = (
|
||||
<>
|
||||
<div className={`w-2.5 h-2.5 rounded-full ${getStatusColor(session.status)} mt-1.5 mr-3 flex-shrink-0`} />
|
||||
<div className="flex-1 min-w-0 pr-1">
|
||||
<div className="font-medium text-sm+ break-words">{session.name}</div>
|
||||
<div className="text-xs text-muted-foreground mt-1 break-words">
|
||||
{session.steps.length} steps • {formatDate(session.updated)}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground mt-0.5 break-words">
|
||||
<span className="capitalize">{session.status}</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return React.createElement(
|
||||
WrapperComponent,
|
||||
{
|
||||
key: session.id,
|
||||
onClick: () => onSelectSession?.(session.id),
|
||||
className: `w-full flex items-start px-3 py-2.5 text-left rounded-md transition-colors hover:bg-accent/50 ${
|
||||
currentSessionId === session.id ? 'bg-accent' : ''
|
||||
}`
|
||||
},
|
||||
closeAction ? (
|
||||
<>
|
||||
{buttonContent}
|
||||
<div className="ml-2 flex-shrink-0 self-center">
|
||||
{React.cloneElement(closeAction as React.ReactElement, {
|
||||
onClick: (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onSelectSession?.(session.id);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
) : buttonContent
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import { AgentSession } from '../utils/types';
|
||||
import { getSampleAgentSessions } from '../utils/sample-data';
|
||||
import { SessionList } from './SessionList';
|
||||
|
||||
interface SessionSidebarProps {
|
||||
onSelectSession?: (sessionId: string) => void;
|
||||
currentSessionId?: string;
|
||||
sessions?: AgentSession[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const SessionSidebar: React.FC<SessionSidebarProps> = ({
|
||||
onSelectSession,
|
||||
currentSessionId,
|
||||
sessions = getSampleAgentSessions(),
|
||||
className = ''
|
||||
}) => {
|
||||
return (
|
||||
<div className={`flex flex-col h-full ${className}`}>
|
||||
<div className="p-4 border-b border-border">
|
||||
<h3 className="font-medium text-lg">Sessions</h3>
|
||||
</div>
|
||||
<SessionList
|
||||
sessions={sessions}
|
||||
currentSessionId={currentSessionId}
|
||||
onSelectSession={onSelectSession}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { TimelineStep } from './TimelineStep';
|
||||
import { AgentStep } from '../utils/types';
|
||||
|
||||
interface TimelineFeedProps {
|
||||
steps: AgentStep[];
|
||||
maxHeight?: string;
|
||||
}
|
||||
|
||||
export const TimelineFeed: React.FC<TimelineFeedProps> = ({
|
||||
steps,
|
||||
maxHeight
|
||||
}) => {
|
||||
// Always use 'desc' (newest first) sort order
|
||||
const sortOrder = 'desc';
|
||||
|
||||
// Sort steps with newest first (desc order)
|
||||
const sortedSteps = useMemo(() => {
|
||||
return [...steps].sort((a, b) => {
|
||||
return b.timestamp.getTime() - a.timestamp.getTime();
|
||||
});
|
||||
}, [steps]);
|
||||
|
||||
return (
|
||||
<div className="w-full rounded-md bg-background">
|
||||
<div
|
||||
className="px-3 py-3 space-y-4 overflow-auto"
|
||||
style={{ maxHeight: maxHeight || undefined }}
|
||||
>
|
||||
{sortedSteps.length > 0 ? (
|
||||
sortedSteps.map((step) => (
|
||||
<TimelineStep key={step.id} step={step} />
|
||||
))
|
||||
) : (
|
||||
<div className="text-center text-muted-foreground py-12 border border-dashed border-border rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8 mx-auto mb-2 text-muted-foreground/50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<p>No steps to display</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import React from 'react';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible';
|
||||
import { AgentStep } from '../utils/types';
|
||||
|
||||
interface TimelineStepProps {
|
||||
step: AgentStep;
|
||||
}
|
||||
|
||||
export const TimelineStep: React.FC<TimelineStepProps> = ({ step }) => {
|
||||
// Get status color
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'completed':
|
||||
return 'bg-green-500';
|
||||
case 'in-progress':
|
||||
return 'bg-blue-500';
|
||||
case 'error':
|
||||
return 'bg-red-500';
|
||||
case 'pending':
|
||||
return 'bg-yellow-500';
|
||||
default:
|
||||
return 'bg-gray-500';
|
||||
}
|
||||
};
|
||||
|
||||
// Get icon based on step type
|
||||
const getTypeIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case 'tool-execution':
|
||||
return '🛠️';
|
||||
case 'thinking':
|
||||
return '💭';
|
||||
case 'planning':
|
||||
return '📝';
|
||||
case 'implementation':
|
||||
return '💻';
|
||||
case 'user-input':
|
||||
return '👤';
|
||||
default:
|
||||
return '▶️';
|
||||
}
|
||||
};
|
||||
|
||||
// Format timestamp
|
||||
const formatTime = (timestamp: Date) => {
|
||||
return timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
};
|
||||
|
||||
return (
|
||||
<Collapsible className="w-full mb-5 border border-border rounded-md overflow-hidden shadow-sm hover:shadow-md transition-all duration-200">
|
||||
<CollapsibleTrigger className="w-full flex items-center justify-between p-4 text-left hover:bg-accent/30 cursor-pointer group">
|
||||
<div className="flex items-center space-x-3 min-w-0 flex-1 pr-3">
|
||||
<div className={`flex-shrink-0 w-3 h-3 rounded-full ${getStatusColor(step.status)} ring-1 ring-ring/20`} />
|
||||
<div className="flex-shrink-0 text-lg group-hover:scale-110 transition-transform">{getTypeIcon(step.type)}</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-medium text-foreground break-words">{step.title}</div>
|
||||
<div className="text-sm text-muted-foreground line-clamp-2">
|
||||
{step.type === 'tool-execution' ? 'Run tool' : step.content.substring(0, 60)}
|
||||
{step.content.length > 60 ? '...' : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground flex flex-col items-end flex-shrink-0 min-w-[70px] text-right">
|
||||
<span className="font-medium">{formatTime(step.timestamp)}</span>
|
||||
{step.duration && (
|
||||
<span className="mt-1 px-2 py-0.5 bg-secondary/50 rounded-full">
|
||||
{(step.duration / 1000).toFixed(1)}s
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<div className="p-5 bg-card/50 border-t border-border">
|
||||
<div className="text-sm break-words text-foreground leading-relaxed">
|
||||
{step.content}
|
||||
</div>
|
||||
{step.duration && (
|
||||
<div className="mt-4 pt-3 border-t border-border/50">
|
||||
<div className="text-xs text-muted-foreground flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-3.5 w-3.5 mr-1"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<polyline points="12 6 12 12 16 14" />
|
||||
</svg>
|
||||
Duration: {(step.duration / 1000).toFixed(1)} seconds
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import * as React from "react";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "../../utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants };
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "../../utils";
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"rounded-xl border bg-card text-card-foreground shadow",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn("font-semibold leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<p
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
));
|
||||
CardContent.displayName = "CardContent";
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import * as React from "react"
|
||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
|
||||
|
||||
import { cn } from "../../utils"
|
||||
|
||||
const Collapsible = CollapsiblePrimitive.Root
|
||||
|
||||
const CollapsibleTrigger = CollapsiblePrimitive.Trigger
|
||||
|
||||
const CollapsibleContent = React.forwardRef<
|
||||
React.ElementRef<typeof CollapsiblePrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<CollapsiblePrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</CollapsiblePrimitive.Content>
|
||||
))
|
||||
CollapsibleContent.displayName = "CollapsibleContent"
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
import { Button } from './button';
|
||||
|
||||
export interface FloatingActionButtonProps {
|
||||
icon: ReactNode;
|
||||
onClick: () => void;
|
||||
ariaLabel?: string;
|
||||
className?: string;
|
||||
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
|
||||
}
|
||||
|
||||
/**
|
||||
* FloatingActionButton component
|
||||
*
|
||||
* A button typically used for primary actions on mobile layouts
|
||||
* Designed to be used with the Layout component's floatingAction prop
|
||||
*/
|
||||
export const FloatingActionButton: React.FC<FloatingActionButtonProps> = ({
|
||||
icon,
|
||||
onClick,
|
||||
ariaLabel = 'Action button',
|
||||
className = '',
|
||||
variant = 'default'
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
variant={variant}
|
||||
size="icon"
|
||||
onClick={onClick}
|
||||
aria-label={ariaLabel}
|
||||
className={`h-14 w-14 rounded-full shadow-xl bg-blue-600 hover:bg-blue-700 text-white flex items-center justify-center border-2 border-white dark:border-gray-800 ${className}`}
|
||||
>
|
||||
{icon}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export * from './button';
|
||||
export * from './card';
|
||||
export * from './collapsible';
|
||||
export * from './floating-action-button';
|
||||
export * from './input';
|
||||
export * from './layout';
|
||||
export * from './sheet';
|
||||
export * from './switch';
|
||||
export * from './scroll-area';
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "../../utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
export { Input };
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Layout component using Tailwind Grid utilities
|
||||
* This component creates a responsive layout with:
|
||||
* - Sticky header at the top (z-index 30)
|
||||
* - Sidebar on desktop (hidden on mobile)
|
||||
* - Main content area with proper positioning
|
||||
* - Optional floating action button for mobile navigation
|
||||
*/
|
||||
export interface LayoutProps {
|
||||
header: React.ReactNode;
|
||||
sidebar?: React.ReactNode;
|
||||
drawer?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
floatingAction?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Layout: React.FC<LayoutProps> = ({
|
||||
header,
|
||||
sidebar,
|
||||
drawer,
|
||||
children,
|
||||
floatingAction
|
||||
}) => {
|
||||
return (
|
||||
<div className="grid min-h-screen grid-cols-1 grid-rows-[64px_1fr] md:grid-cols-[280px_1fr] lg:grid-cols-[320px_1fr] xl:grid-cols-[350px_1fr] bg-background text-foreground relative">
|
||||
{/* Header - always visible, spans full width */}
|
||||
<header className="sticky top-0 z-30 h-16 flex items-center bg-background border-b border-border col-span-full">
|
||||
{header}
|
||||
</header>
|
||||
|
||||
{/* Sidebar - hidden on mobile, visible on tablet/desktop */}
|
||||
{sidebar && (
|
||||
<aside className="hidden md:block fixed top-16 bottom-0 w-[280px] lg:w-[320px] xl:w-[350px] overflow-y-auto z-20 bg-background border-r border-border">
|
||||
{sidebar}
|
||||
</aside>
|
||||
)}
|
||||
|
||||
{/* Main content area */}
|
||||
<main className="overflow-y-auto p-4 row-start-2 col-start-1 md:col-start-2 md:h-[calc(100vh-64px)]">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
{/* Mobile drawer - rendered outside grid */}
|
||||
{drawer}
|
||||
|
||||
{/* Floating action button for mobile */}
|
||||
{floatingAction && (
|
||||
<div className="fixed bottom-6 right-6 z-50 md:hidden">
|
||||
{floatingAction}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
|
||||
import { cn } from "../../utils"
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollBar orientation="horizontal" />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import * as React from "react"
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "../../utils"
|
||||
|
||||
const Sheet = SheetPrimitive.Root
|
||||
|
||||
const SheetTrigger = SheetPrimitive.Trigger
|
||||
|
||||
const SheetClose = SheetPrimitive.Close
|
||||
|
||||
const SheetPortal = SheetPrimitive.Portal
|
||||
|
||||
const SheetOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-70 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
))
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
||||
|
||||
const sheetVariants = cva(
|
||||
"fixed z-70 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
||||
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
||||
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
||||
left: "inset-y-0 left-0 h-full w-full border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
interface SheetContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {}
|
||||
|
||||
const SheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||
SheetContentProps
|
||||
>(({ side = "right", className, children, ...props }, ref) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(sheetVariants({ side }), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
))
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName
|
||||
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetHeader.displayName = "SheetHeader"
|
||||
|
||||
const SheetFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetFooter.displayName = "SheetFooter"
|
||||
|
||||
const SheetTitle = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
||||
|
||||
const SheetDescription = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
SheetTrigger,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import * as React from "react";
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||
|
||||
import { cn } from "../../utils";
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
));
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName;
|
||||
|
||||
export { Switch };
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Entry point for @ra-aid/common package
|
||||
import './styles/global.css';
|
||||
|
||||
// Export types first to avoid circular references
|
||||
export * from './utils/types';
|
||||
|
||||
// Export utility functions
|
||||
export * from './utils';
|
||||
|
||||
// Export UI components
|
||||
export * from './components/ui';
|
||||
|
||||
// Export timeline components
|
||||
export * from './components/TimelineStep';
|
||||
export * from './components/TimelineFeed';
|
||||
|
||||
// Export session navigation components
|
||||
export * from './components/SessionDrawer';
|
||||
export * from './components/SessionSidebar';
|
||||
|
||||
// Export main screens
|
||||
export * from './components/DefaultAgentScreen';
|
||||
|
||||
// Export the hello function (temporary example)
|
||||
export const hello = (): void => {
|
||||
console.log("Hello from @ra-aid/common");
|
||||
};
|
||||
|
||||
// Directly export sample data functions
|
||||
export {
|
||||
getSampleAgentSteps,
|
||||
getSampleAgentSessions
|
||||
} from './utils/sample-data';
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 100% 50%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 215 20.2% 65.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 240 10% 3.9%; /* zinc-950 */
|
||||
--foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--card: 240 10% 3.9%; /* zinc-950 */
|
||||
--card-foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--popover: 240 10% 3.9%; /* zinc-950 */
|
||||
--popover-foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--primary: 240 5% 96%; /* zinc-50 */
|
||||
--primary-foreground: 240 6% 10%; /* zinc-900 */
|
||||
|
||||
--secondary: 240 4% 16%; /* zinc-800 */
|
||||
--secondary-foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--muted: 240 4% 16%; /* zinc-800 */
|
||||
--muted-foreground: 240 5% 65%; /* zinc-400 */
|
||||
|
||||
--accent: 240 4% 16%; /* zinc-800 */
|
||||
--accent-foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--destructive: 0 63% 31%; /* red-900 */
|
||||
--destructive-foreground: 240 5% 96%; /* zinc-50 */
|
||||
|
||||
--border: 240 4% 16%; /* zinc-800 */
|
||||
--input: 240 4% 16%; /* zinc-800 */
|
||||
--ring: 240 5% 84%; /* zinc-300 */
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-feature-settings: "rlig" 1, "calt" 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
declare module '*.png' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.jpeg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
/**
|
||||
* Merges class names with Tailwind CSS classes
|
||||
* Combines clsx for conditional logic and tailwind-merge for handling conflicting tailwind classes
|
||||
*/
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
// Re-export everything from utils directory
|
||||
export * from './utils';
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
/**
|
||||
* Merges class names with Tailwind CSS classes
|
||||
* Combines clsx for conditional logic and tailwind-merge for handling conflicting tailwind classes
|
||||
*/
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
// Note: Sample data functions and types are now exported directly from the root index.ts
|
||||
// to avoid circular references
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* Sample data utility for agent UI components demonstration
|
||||
*/
|
||||
|
||||
import { AgentStep, AgentSession } from './types';
|
||||
|
||||
/**
|
||||
* Returns an array of sample agent steps
|
||||
*/
|
||||
export function getSampleAgentSteps(): AgentStep[] {
|
||||
return [
|
||||
{
|
||||
id: "step-1",
|
||||
timestamp: new Date(Date.now() - 30 * 60000), // 30 minutes ago
|
||||
status: 'completed',
|
||||
type: 'planning',
|
||||
title: 'Initial Planning',
|
||||
content: 'I need to analyze the codebase structure to understand the existing components and their relationships.',
|
||||
duration: 5200
|
||||
},
|
||||
{
|
||||
id: "step-2",
|
||||
timestamp: new Date(Date.now() - 25 * 60000), // 25 minutes ago
|
||||
status: 'completed',
|
||||
type: 'tool-execution',
|
||||
title: 'List Directory Structure',
|
||||
content: 'Executing: list_directory_tree(path="src/", max_depth=2)\n\n📁 /project/src/\n├── 📁 components/\n│ ├── 📁 ui/\n│ └── App.tsx\n├── 📁 utils/\n└── index.tsx',
|
||||
duration: 1800
|
||||
},
|
||||
{
|
||||
id: "step-3",
|
||||
timestamp: new Date(Date.now() - 20 * 60000), // 20 minutes ago
|
||||
status: 'completed',
|
||||
type: 'thinking',
|
||||
title: 'Component Analysis',
|
||||
content: 'Based on the directory structure, I see that the UI components are organized in a dedicated folder. I should examine the existing component patterns before implementing new ones.',
|
||||
duration: 3500
|
||||
},
|
||||
{
|
||||
id: "step-4",
|
||||
timestamp: new Date(Date.now() - 15 * 60000), // 15 minutes ago
|
||||
status: 'completed',
|
||||
type: 'tool-execution',
|
||||
title: 'Read Component Code',
|
||||
content: 'Executing: read_file_tool(filepath="src/components/ui/Button.tsx")\n\n```tsx\nimport { cn } from "../../utils";\n\nexport interface ButtonProps {\n // Component props...\n}\n\nexport function Button({ children, ...props }: ButtonProps) {\n // Component implementation...\n}\n```',
|
||||
duration: 2100
|
||||
},
|
||||
{
|
||||
id: "step-5",
|
||||
timestamp: new Date(Date.now() - 10 * 60000), // 10 minutes ago
|
||||
status: 'completed',
|
||||
type: 'implementation',
|
||||
title: 'Creating NavBar Component',
|
||||
content: 'I\'m creating a NavBar component following the design system patterns:\n\n```tsx\nimport { cn } from "../../utils";\n\nexport interface NavBarProps {\n // New component props...\n}\n\nexport function NavBar({ ...props }: NavBarProps) {\n // New component implementation...\n}\n```',
|
||||
duration: 6800
|
||||
},
|
||||
{
|
||||
id: "step-6",
|
||||
timestamp: new Date(Date.now() - 5 * 60000), // 5 minutes ago
|
||||
status: 'in-progress',
|
||||
type: 'implementation',
|
||||
title: 'Styling Timeline Component',
|
||||
content: 'Currently working on styling the Timeline component to match the design system:\n\n```tsx\n// Work in progress...\nexport function Timeline({ steps, ...props }: TimelineProps) {\n // Current implementation...\n}\n```',
|
||||
},
|
||||
{
|
||||
id: "step-7",
|
||||
timestamp: new Date(Date.now() - 2 * 60000), // 2 minutes ago
|
||||
status: 'error',
|
||||
type: 'tool-execution',
|
||||
title: 'Running Tests',
|
||||
content: 'Error executing: run_shell_command(command="npm test")\n\nTest failed: TypeError: Cannot read property \'steps\' of undefined',
|
||||
duration: 3200
|
||||
},
|
||||
{
|
||||
id: "step-8",
|
||||
timestamp: new Date(), // Now
|
||||
status: 'pending',
|
||||
type: 'planning',
|
||||
title: 'Next Steps',
|
||||
content: 'Need to plan the implementation of the SessionDrawer component...',
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sample agent sessions
|
||||
*/
|
||||
export function getSampleAgentSessions(): AgentSession[] {
|
||||
const steps = getSampleAgentSteps();
|
||||
|
||||
return [
|
||||
{
|
||||
id: "session-1",
|
||||
name: "UI Component Implementation",
|
||||
created: new Date(Date.now() - 35 * 60000), // 35 minutes ago
|
||||
updated: new Date(), // Now
|
||||
status: 'active',
|
||||
steps: steps
|
||||
},
|
||||
{
|
||||
id: "session-2",
|
||||
name: "API Integration",
|
||||
created: new Date(Date.now() - 2 * 3600000), // 2 hours ago
|
||||
updated: new Date(Date.now() - 30 * 60000), // 30 minutes ago
|
||||
status: 'completed',
|
||||
steps: [
|
||||
{
|
||||
id: "other-step-1",
|
||||
timestamp: new Date(Date.now() - 2 * 3600000), // 2 hours ago
|
||||
status: 'completed',
|
||||
type: 'planning',
|
||||
title: 'API Integration Planning',
|
||||
content: 'Planning the integration with the backend API...',
|
||||
duration: 4500
|
||||
},
|
||||
{
|
||||
id: "other-step-2",
|
||||
timestamp: new Date(Date.now() - 1.5 * 3600000), // 1.5 hours ago
|
||||
status: 'completed',
|
||||
type: 'implementation',
|
||||
title: 'Implementing API Client',
|
||||
content: 'Creating API client with fetch utilities...',
|
||||
duration: 7200
|
||||
},
|
||||
{
|
||||
id: "other-step-3",
|
||||
timestamp: new Date(Date.now() - 1 * 3600000), // 1 hour ago
|
||||
status: 'completed',
|
||||
type: 'tool-execution',
|
||||
title: 'Testing API Endpoints',
|
||||
content: 'Running tests against API endpoints...',
|
||||
duration: 5000
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "session-3",
|
||||
name: "Bug Fixes",
|
||||
created: new Date(Date.now() - 5 * 3600000), // 5 hours ago
|
||||
updated: new Date(Date.now() - 4 * 3600000), // 4 hours ago
|
||||
status: 'error',
|
||||
steps: [
|
||||
{
|
||||
id: "bug-step-1",
|
||||
timestamp: new Date(Date.now() - 5 * 3600000), // 5 hours ago
|
||||
status: 'completed',
|
||||
type: 'planning',
|
||||
title: 'Bug Analysis',
|
||||
content: 'Analyzing reported bugs from issue tracker...',
|
||||
duration: 3600
|
||||
},
|
||||
{
|
||||
id: "bug-step-2",
|
||||
timestamp: new Date(Date.now() - 4.5 * 3600000), // 4.5 hours ago
|
||||
status: 'error',
|
||||
type: 'implementation',
|
||||
title: 'Fixing Authentication Bug',
|
||||
content: 'Error: Unable to resolve dependency conflict with auth package',
|
||||
duration: 2500
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Common types for agent UI components
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a single step in the agent process
|
||||
*/
|
||||
export interface AgentStep {
|
||||
id: string;
|
||||
timestamp: Date;
|
||||
status: 'completed' | 'in-progress' | 'error' | 'pending';
|
||||
type: 'tool-execution' | 'thinking' | 'planning' | 'implementation' | 'user-input';
|
||||
title: string;
|
||||
content: string;
|
||||
duration?: number; // in milliseconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a session with multiple steps
|
||||
*/
|
||||
export interface AgentSession {
|
||||
id: string;
|
||||
name: string;
|
||||
created: Date;
|
||||
updated: Date;
|
||||
status: 'active' | 'completed' | 'error';
|
||||
steps: AgentStep[];
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [require('./tailwind.preset')],
|
||||
content: [
|
||||
'./src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
safelist: [
|
||||
'dark',
|
||||
{
|
||||
pattern: /^dark:/,
|
||||
variants: ['hover', 'focus', 'active']
|
||||
}
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"jsx": "react",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext", "ES2016"]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "frontend-monorepo",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"common",
|
||||
"web",
|
||||
"vsc"
|
||||
],
|
||||
"scripts": {
|
||||
"install-all": "npm install",
|
||||
"dev:web": "npm --workspace @ra-aid/web run dev"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { defineConfig } from '@vscode/test-cli';
|
||||
|
||||
export default defineConfig({
|
||||
files: 'out/test/**/*.test.js',
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"]
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true, // set this to false to include "out" folder in search results
|
||||
"dist": true // set this to false to include "dist" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "watch",
|
||||
"dependsOn": [
|
||||
"npm: watch:tsc",
|
||||
"npm: watch:esbuild"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:esbuild",
|
||||
"group": "build",
|
||||
"problemMatcher": "$esbuild-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:esbuild",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch:tsc",
|
||||
"group": "build",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"label": "npm: watch:tsc",
|
||||
"presentation": {
|
||||
"group": "watch",
|
||||
"reveal": "never"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-tests",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"group": "watchers"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "tasks: watch-tests",
|
||||
"dependsOn": [
|
||||
"npm: watch",
|
||||
"npm: watch-tests"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
.vscode/**
|
||||
.vscode-test/**
|
||||
out/**
|
||||
node_modules/**
|
||||
src/**
|
||||
.gitignore
|
||||
.yarnrc
|
||||
esbuild.js
|
||||
vsc-extension-quickstart.md
|
||||
**/tsconfig.json
|
||||
**/eslint.config.mjs
|
||||
**/*.map
|
||||
**/*.ts
|
||||
**/.vscode-test.*
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to the "ra-aid" extension will be documented in this file.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Initial release
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# ra-aid README
|
||||
|
||||
This is the README for your extension "ra-aid". After writing up a brief description, we recommend including the following sections.
|
||||
|
||||
## Features
|
||||
|
||||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
||||
|
||||
For example if there is an image subfolder under your extension project workspace:
|
||||
|
||||
\!\[feature X\]\(images/feature-x.png\)
|
||||
|
||||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
||||
|
||||
## Requirements
|
||||
|
||||
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
|
||||
|
||||
## Extension Settings
|
||||
|
||||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
|
||||
|
||||
For example:
|
||||
|
||||
This extension contributes the following settings:
|
||||
|
||||
* `myExtension.enable`: Enable/disable this extension.
|
||||
* `myExtension.thing`: Set to `blah` to do something.
|
||||
|
||||
## Known Issues
|
||||
|
||||
Calling out known issues can help limit users opening duplicate issues against your extension.
|
||||
|
||||
## Release Notes
|
||||
|
||||
Users appreciate release notes as you update your extension.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
Initial release of ...
|
||||
|
||||
### 1.0.1
|
||||
|
||||
Fixed issue #.
|
||||
|
||||
### 1.1.0
|
||||
|
||||
Added features X, Y, and Z.
|
||||
|
||||
---
|
||||
|
||||
## Following extension guidelines
|
||||
|
||||
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
|
||||
|
||||
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
|
||||
|
||||
## Working with Markdown
|
||||
|
||||
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
|
||||
|
||||
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
|
||||
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
|
||||
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
|
||||
|
||||
## For more information
|
||||
|
||||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
|
||||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
|
||||
|
||||
**Enjoy!**
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
|
|
@ -0,0 +1,140 @@
|
|||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/extension.ts
|
||||
var extension_exports = {};
|
||||
__export(extension_exports, {
|
||||
activate: () => activate,
|
||||
deactivate: () => deactivate
|
||||
});
|
||||
module.exports = __toCommonJS(extension_exports);
|
||||
var vscode = __toESM(require("vscode"));
|
||||
var RAWebviewViewProvider = class {
|
||||
constructor(_extensionUri) {
|
||||
this._extensionUri = _extensionUri;
|
||||
}
|
||||
/**
|
||||
* Called when a view is first created to initialize the webview
|
||||
*/
|
||||
resolveWebviewView(webviewView, context, _token) {
|
||||
webviewView.webview.options = {
|
||||
// Enable JavaScript in the webview
|
||||
enableScripts: true,
|
||||
// Restrict the webview to only load resources from the extension's directory
|
||||
localResourceRoots: [this._extensionUri]
|
||||
};
|
||||
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
|
||||
}
|
||||
/**
|
||||
* Creates HTML content for the webview with proper security policies
|
||||
*/
|
||||
_getHtmlForWebview(webview) {
|
||||
const logoUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "RA.png"));
|
||||
const nonce = getNonce();
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}';">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RA.Aid</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
color: var(--vscode-foreground);
|
||||
font-size: var(--vscode-font-size);
|
||||
font-weight: var(--vscode-font-weight);
|
||||
font-family: var(--vscode-font-family);
|
||||
background-color: var(--vscode-editor-background);
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.logo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
color: var(--vscode-editor-foreground);
|
||||
font-size: 1.3em;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p {
|
||||
color: var(--vscode-foreground);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<img src="${logoUri}" alt="RA.Aid Logo" class="logo">
|
||||
<h1>RA.Aid</h1>
|
||||
<p>Your research and development assistant.</p>
|
||||
<p>More features coming soon!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
};
|
||||
function getNonce() {
|
||||
let text = "";
|
||||
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (let i = 0; i < 32; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
function activate(context) {
|
||||
console.log('Congratulations, your extension "ra-aid" is now active!');
|
||||
const provider = new RAWebviewViewProvider(context.extensionUri);
|
||||
const viewRegistration = vscode.window.registerWebviewViewProvider(
|
||||
"ra-aid.view",
|
||||
// Must match the view id in package.json
|
||||
provider
|
||||
);
|
||||
context.subscriptions.push(viewRegistration);
|
||||
const disposable = vscode.commands.registerCommand("ra-aid.helloWorld", () => {
|
||||
vscode.window.showInformationMessage("Hello World from RA.Aid!");
|
||||
});
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
function deactivate() {
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
activate,
|
||||
deactivate
|
||||
});
|
||||
//# sourceMappingURL=extension.js.map
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"version": 3,
|
||||
"sources": ["../src/extension.ts"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,aAAwB;AAKxB,IAAM,wBAAN,MAAkE;AAAA,EAChE,YAA6B,eAA2B;AAA3B;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA,EAKlD,mBACL,aACA,SACA,QACA;AAEA,gBAAY,QAAQ,UAAU;AAAA;AAAA,MAE5B,eAAe;AAAA;AAAA,MAEf,oBAAoB,CAAC,KAAK,aAAa;AAAA,IACzC;AAGA,gBAAY,QAAQ,OAAO,KAAK,mBAAmB,YAAY,OAAO;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,SAAiC;AAE1D,UAAM,UAAU,QAAQ,aAAoB,WAAI,SAAS,KAAK,eAAe,UAAU,QAAQ,CAAC;AAMhG,UAAM,QAAQ,SAAS;AAEvB,WAAO;AAAA;AAAA;AAAA;AAAA,0FAI+E,QAAQ,SAAS,sBAAsB,QAAQ,SAAS,uCAAuC,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAsCxK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3B;AACF;AAKA,SAAS,WAAW;AAClB,MAAI,OAAO;AACX,QAAM,WAAW;AACjB,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAQ,SAAS,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,SAAS,MAAM,CAAC;AAAA,EACrE;AACA,SAAO;AACT;AAGO,SAAS,SAAS,SAAkC;AAEzD,UAAQ,IAAI,yDAAyD;AAGrE,QAAM,WAAW,IAAI,sBAAsB,QAAQ,YAAY;AAC/D,QAAM,mBAA0B,cAAO;AAAA,IACrC;AAAA;AAAA,IACA;AAAA,EACF;AACA,UAAQ,cAAc,KAAK,gBAAgB;AAK3C,QAAM,aAAoB,gBAAS,gBAAgB,qBAAqB,MAAM;AAG5E,IAAO,cAAO,uBAAuB,0BAA0B;AAAA,EACjE,CAAC;AAED,UAAQ,cAAc,KAAK,UAAU;AACvC;AAGO,SAAS,aAAa;AAAC;",
|
||||
"names": []
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
const esbuild = require("esbuild");
|
||||
|
||||
const production = process.argv.includes('--production');
|
||||
const watch = process.argv.includes('--watch');
|
||||
|
||||
/**
|
||||
* @type {import('esbuild').Plugin}
|
||||
*/
|
||||
const esbuildProblemMatcherPlugin = {
|
||||
name: 'esbuild-problem-matcher',
|
||||
|
||||
setup(build) {
|
||||
build.onStart(() => {
|
||||
console.log('[watch] build started');
|
||||
});
|
||||
build.onEnd((result) => {
|
||||
result.errors.forEach(({ text, location }) => {
|
||||
console.error(`✘ [ERROR] ${text}`);
|
||||
console.error(` ${location.file}:${location.line}:${location.column}:`);
|
||||
});
|
||||
console.log('[watch] build finished');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: [
|
||||
'src/extension.ts'
|
||||
],
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
platform: 'node',
|
||||
outfile: 'dist/extension.js',
|
||||
external: ['vscode'],
|
||||
logLevel: 'silent',
|
||||
plugins: [
|
||||
/* add to the end of plugins array */
|
||||
esbuildProblemMatcherPlugin,
|
||||
],
|
||||
});
|
||||
if (watch) {
|
||||
await ctx.watch();
|
||||
} else {
|
||||
await ctx.rebuild();
|
||||
await ctx.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
|
||||
export default [{
|
||||
files: ["**/*.ts"],
|
||||
}, {
|
||||
plugins: {
|
||||
"@typescript-eslint": typescriptEslint,
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
},
|
||||
|
||||
rules: {
|
||||
"@typescript-eslint/naming-convention": ["warn", {
|
||||
selector: "import",
|
||||
format: ["camelCase", "PascalCase"],
|
||||
}],
|
||||
|
||||
curly: "warn",
|
||||
eqeqeq: "warn",
|
||||
"no-throw-literal": "warn",
|
||||
semi: "warn",
|
||||
},
|
||||
}];
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "ra-aid",
|
||||
"displayName": "RA.Aid",
|
||||
"description": "Develop software autonomously.",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.98.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "ra-aid-view",
|
||||
"title": "RA.Aid",
|
||||
"icon": "assets/RA-white-transp.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"ra-aid-view": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "ra-aid.view",
|
||||
"name": "RA.Aid"
|
||||
}
|
||||
]
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "ra-aid.helloWorld",
|
||||
"title": "Hello World"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:esbuild": "node esbuild.js --watch",
|
||||
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
|
||||
"package": "npm run check-types && npm run lint && node esbuild.js --production",
|
||||
"compile-tests": "tsc -p . --outDir out",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"check-types": "tsc --noEmit",
|
||||
"lint": "eslint src",
|
||||
"test": "vscode-test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.98.0",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "20.x",
|
||||
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
||||
"@typescript-eslint/parser": "^8.25.0",
|
||||
"eslint": "^9.21.0",
|
||||
"esbuild": "^0.25.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.7.3",
|
||||
"@vscode/test-cli": "^0.0.10",
|
||||
"@vscode/test-electron": "^2.4.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
// The module 'vscode' contains the VS Code extensibility API
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* WebviewViewProvider implementation for the RA.Aid panel
|
||||
*/
|
||||
class RAWebviewViewProvider implements vscode.WebviewViewProvider {
|
||||
constructor(private readonly _extensionUri: vscode.Uri) {}
|
||||
|
||||
/**
|
||||
* Called when a view is first created to initialize the webview
|
||||
*/
|
||||
public resolveWebviewView(
|
||||
webviewView: vscode.WebviewView,
|
||||
context: vscode.WebviewViewResolveContext,
|
||||
_token: vscode.CancellationToken
|
||||
) {
|
||||
// Set options for the webview
|
||||
webviewView.webview.options = {
|
||||
// Enable JavaScript in the webview
|
||||
enableScripts: true,
|
||||
// Restrict the webview to only load resources from the extension's directory
|
||||
localResourceRoots: [this._extensionUri]
|
||||
};
|
||||
|
||||
// Set the HTML content of the webview
|
||||
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates HTML content for the webview with proper security policies
|
||||
*/
|
||||
private _getHtmlForWebview(webview: vscode.Webview): string {
|
||||
// Create a URI to the extension's assets directory
|
||||
const logoUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'assets', 'RA.png'));
|
||||
|
||||
// Create a URI to the script file
|
||||
// const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'dist', 'webview.js'));
|
||||
|
||||
// Use a nonce to whitelist scripts
|
||||
const nonce = getNonce();
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webview.cspSource} https:; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}';">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RA.Aid</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
color: var(--vscode-foreground);
|
||||
font-size: var(--vscode-font-size);
|
||||
font-weight: var(--vscode-font-weight);
|
||||
font-family: var(--vscode-font-family);
|
||||
background-color: var(--vscode-editor-background);
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.logo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
color: var(--vscode-editor-foreground);
|
||||
font-size: 1.3em;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p {
|
||||
color: var(--vscode-foreground);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<img src="${logoUri}" alt="RA.Aid Logo" class="logo">
|
||||
<h1>RA.Aid</h1>
|
||||
<p>Your research and development assistant.</p>
|
||||
<p>More features coming soon!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random nonce for CSP
|
||||
*/
|
||||
function getNonce() {
|
||||
let text = '';
|
||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
for (let i = 0; i < 32; i++) {
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// This method is called when your extension is activated
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
// Use the console to output diagnostic information (console.log) and errors (console.error)
|
||||
console.log('Congratulations, your extension "ra-aid" is now active!');
|
||||
|
||||
// Register the WebviewViewProvider
|
||||
const provider = new RAWebviewViewProvider(context.extensionUri);
|
||||
const viewRegistration = vscode.window.registerWebviewViewProvider(
|
||||
'ra-aid.view', // Must match the view id in package.json
|
||||
provider
|
||||
);
|
||||
context.subscriptions.push(viewRegistration);
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
const disposable = vscode.commands.registerCommand('ra-aid.helloWorld', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage('Hello World from RA.Aid!');
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
|
||||
// This method is called when your extension is deactivated
|
||||
export function deactivate() {}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../../extension';
|
||||
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "Node16",
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"ES2022"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true, /* enable all strict type-checking options */
|
||||
/* Additional Checks */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# Welcome to your VS Code Extension
|
||||
|
||||
## What's in the folder
|
||||
|
||||
* This folder contains all of the files necessary for your extension.
|
||||
* `package.json` - this is the manifest file in which you declare your extension and command.
|
||||
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
|
||||
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
|
||||
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
|
||||
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
|
||||
|
||||
## Setup
|
||||
|
||||
* install the recommended extensions (amodio.tsl-problem-matcher, ms-vscode.extension-test-runner, and dbaeumer.vscode-eslint)
|
||||
|
||||
|
||||
## Get up and running straight away
|
||||
|
||||
* Press `F5` to open a new window with your extension loaded.
|
||||
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
|
||||
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
|
||||
* Find output from your extension in the debug console.
|
||||
|
||||
## Make changes
|
||||
|
||||
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
|
||||
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
||||
|
||||
|
||||
## Explore the API
|
||||
|
||||
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
|
||||
|
||||
## Run tests
|
||||
|
||||
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
|
||||
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
|
||||
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
|
||||
* See the output of the test result in the Test Results view.
|
||||
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
|
||||
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
|
||||
* You can create folders inside the `test` folder to structure your tests any way you want.
|
||||
|
||||
## Go further
|
||||
|
||||
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
|
||||
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
|
||||
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Demo page showcasing shadcn/ui components from the common package" />
|
||||
<title>RA-Aid UI Components Demo</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "@ra-aid/web",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"@ra-aid/common": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^4.0.0",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"postcss": "^8.4.35",
|
||||
"autoprefixer": "^10.4.17"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { DefaultAgentScreen } from '@ra-aid/common';
|
||||
|
||||
/**
|
||||
* Main application entry point
|
||||
* Simply renders the DefaultAgentScreen component from the common package
|
||||
*/
|
||||
const App = () => {
|
||||
return <DefaultAgentScreen />;
|
||||
};
|
||||
|
||||
// Mount the app to the root element
|
||||
const root = ReactDOM.createRoot(document.getElementById('root')!);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [require('../common/tailwind.preset')],
|
||||
content: [
|
||||
'./src/**/*.{js,jsx,ts,tsx}',
|
||||
'../common/src/**/*.{js,jsx,ts,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms')
|
||||
],
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
// Get all component files from common package
|
||||
const commonSrcDir = path.resolve(__dirname, '../common/src');
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
// Direct alias to the source directory
|
||||
'@ra-aid/common': path.resolve(__dirname, '../common/src')
|
||||
},
|
||||
preserveSymlinks: true
|
||||
},
|
||||
optimizeDeps: {
|
||||
// Exclude the common package from optimization so it can trigger hot reload
|
||||
exclude: ['@ra-aid/common']
|
||||
},
|
||||
server: {
|
||||
hmr: true,
|
||||
watch: {
|
||||
usePolling: true,
|
||||
interval: 100,
|
||||
// Make sure to explicitly NOT ignore the common package
|
||||
ignored: [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'!**/common/src/**'
|
||||
]
|
||||
}
|
||||
},
|
||||
build: {
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -22,20 +22,21 @@ classifiers = [
|
|||
"Topic :: Software Development :: Libraries :: Python Modules"
|
||||
]
|
||||
dependencies = [
|
||||
"langchain-anthropic>=0.3.7",
|
||||
"langchain-openai>=0.3.5",
|
||||
"langchain-google-genai>=2.0.9",
|
||||
"langgraph>=0.2.73",
|
||||
"langgraph-checkpoint>=2.0.12",
|
||||
"langchain-core>=0.3.35",
|
||||
"langchain>=0.3.18",
|
||||
"langchain-anthropic>=0.3.9",
|
||||
"langchain-openai>=0.3.8",
|
||||
"langchain-google-genai>=2.0.11",
|
||||
"langgraph>=0.3.5",
|
||||
"langgraph-checkpoint>=2.0.18",
|
||||
"langchain-core>=0.3.5",
|
||||
"langgraph-prebuilt>=0.1.2",
|
||||
"langchain>=0.3.5",
|
||||
"rich>=13.0.0",
|
||||
"GitPython>=3.1",
|
||||
"fuzzywuzzy==0.18.0",
|
||||
"rapidfuzz>=3.11.0",
|
||||
"pathspec>=0.11.0",
|
||||
"pyte>=0.8.2",
|
||||
"aider-chat>=0.74.2",
|
||||
"aider-chat>=0.75.1",
|
||||
"tavily-python>=0.5.0",
|
||||
"litellm>=1.60.6",
|
||||
"fastapi>=0.104.0",
|
||||
|
|
@ -43,6 +44,13 @@ dependencies = [
|
|||
"websockets>=12.0",
|
||||
"jinja2>=3.1.2",
|
||||
"python-Levenshtein>=0.26.1",
|
||||
"python-magic>=0.4.27",
|
||||
"peewee>=3.17.9",
|
||||
"peewee-migrate>=1.13.0",
|
||||
"platformdirs>=3.17.9",
|
||||
"requests",
|
||||
"packaging",
|
||||
"prompt-toolkit"
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,3 +1,3 @@
|
|||
"""Version information."""
|
||||
|
||||
__version__ = "0.14.2"
|
||||
__version__ = "0.17.1"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue