opalacoder 0.2.0__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opalacoder-0.2.3/AppIcons/icon.png +0 -0
- opalacoder-0.2.3/AppIcons/opalaicon.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/PKG-INFO +1 -1
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/07-configuracao.md +217 -1
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/src/App.jsx +111 -3
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/src/index.css +5 -0
- opalacoder-0.2.3/icon.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/agent_stdin.py +16 -2
- opalacoder-0.2.3/opalacoder/assetstore/modelconfigs/gpt_oss__latest.metadata +4 -0
- opalacoder-0.2.3/opalacoder/assetstore/modelconfigs/gpt_oss__latest.zip +0 -0
- opalacoder-0.2.3/opalacoder/assetstore/skills/skill_html_css_js.metadata +4 -0
- opalacoder-0.2.3/opalacoder/assetstore/skills/skill_html_css_js.zip +0 -0
- opalacoder-0.2.3/opalacoder/assetstore/skills/skill_implement_feature.metadata +4 -0
- opalacoder-0.2.3/opalacoder/assetstore/skills/skill_implement_feature.zip +0 -0
- opalacoder-0.2.3/opalacoder/assetstore.py +179 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/cli_commands.py +78 -0
- opalacoder-0.2.3/opalacoder/gui/assets/index-CD7_Sjss.css +32 -0
- opalacoder-0.2.3/opalacoder/gui/assets/index-DYKstQJF.js +159 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/gui/index.html +2 -2
- opalacoder-0.2.3/opalacoder/icon.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/ide_server.py +58 -1
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/memgpt_runtime.py +2 -1
- {opalacoder-0.2.0 → opalacoder-0.2.3}/pyproject.toml +1 -1
- opalacoder-0.2.0/opalacoder/gui/assets/index-BqTKFzta.js +0 -159
- opalacoder-0.2.0/opalacoder/gui/assets/index-_ON06SYj.css +0 -32
- opalacoder-0.2.0/opalacoder/icon.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/.claude/rules/RULES.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/.claude/settings.json +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/.github/workflows/publish.yml +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/.gitignore +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AGENTS.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/100.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/102.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/108.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/114.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/120.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/128.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/144.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/152.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/16.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/167.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/172.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/180.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/196.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/20.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/216.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/234.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/256.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/258.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/29.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/32.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/40.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/48.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/50.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/512.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/55.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/57.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/58.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/60.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/64.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/66.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/72.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/76.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/80.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/87.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/88.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/92.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/android/mipmap-hdpi/ic_launcher.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/android/mipmap-mdpi/ic_launcher.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/android/mipmap-xhdpi/ic_launcher.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/android/mipmap-xxhdpi/ic_launcher.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/android/mipmap-xxxhdpi/ic_launcher.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/appstore.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/AppIcons/playstore.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/CLAUDE.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/GEMINI.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/README.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/agents.yaml +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/config.yaml +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3/debug}/debug_litellm_callbacks.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/debug/scratch_tail.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3/debug}/test_thought_stream.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/guide/analysis_results.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/guide/figs/logotipo.png +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/guide/paper_memplan.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/guide/skills-plugin-system.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/01-arquitetura.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/02-memgpt-orquestrador.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/03-skill-implement-feature.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/04-memoria.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/05-vcs-sombra.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/06-skills-e-plugins.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/08-ide.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/09-ide-projectcreationinterface.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/README.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/docs/specs/backlog_register.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/index.html +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/package-lock.json +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/package.json +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/src/main.jsx +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/gui_src/vite.config.js +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/main.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/__init__.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/agents.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/api_keys.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/archival.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/cli.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/code_index.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/config.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/embeddings.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/gui/assets/vendor-monaco-BkbU5OES.js +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/gui/assets/vendor-react-B2vUwPEE.js +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/gui/assets/vendor-xterm-3VOAfa_q.js +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/i18n.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/orchestrator.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/planner.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/plugins/__init__.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/plugins/html_css_js_tools.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/project.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/session.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/skills.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/structured.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/terminal.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/terminal_manager.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/tools.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/vcs.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/vector_index.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/workflow_orchestrator.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/opalacoder/workflow_tools.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/pytest.ini +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/requirements.txt +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/chat-orchestrator/SKILL.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/command-line/SKILL.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/command-line/scripts/command_executor.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/skills_store/html-css-js/SKILL.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/skills_store/html-css-js/scripts/check_contracts.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/skills_store/implement-feature/SKILL.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/skills_store/implement-feature/scripts/run_workflow.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/view-editor/SKILL.md +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/skills/view-editor/scripts/run_view_editor.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_agent_config.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_agent_stdin.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_code_index_integration.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_command_line_skill.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_complexity_evaluator.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_context_guard.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_file_delete.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_i18n_coverage.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_implement_feature_script.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_memgpt_runtime.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_model_commands.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_planner_oracle_live.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_planner_output.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_project_store.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_refinement_loop.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_search_bugs.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_skills_directory_loader.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_unhashable_dict_bug.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_verification_strategies.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_view_editor_skill.py +0 -0
- {opalacoder-0.2.0 → opalacoder-0.2.3}/tests/test_workflow_pipeline.py +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opalacoder
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Autonomous coding agent with interactive planning and modular execution
|
|
5
5
|
Project-URL: Homepage, https://github.com/gilzamir/OpalaCoder
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/gilzamir/OpalaCoder/issues
|
|
@@ -141,7 +141,223 @@ De `build_parser` ([cli.py:419](../../opalacoder/cli.py#L419)):
|
|
|
141
141
|
|
|
142
142
|
---
|
|
143
143
|
|
|
144
|
-
## 5.
|
|
144
|
+
## 5. AssetStore — Repositório de Assets Reutilizáveis
|
|
145
|
+
|
|
146
|
+
> **Estado: IMPLEMENTADO**
|
|
147
|
+
|
|
148
|
+
### Conceito
|
|
149
|
+
|
|
150
|
+
A AssetStore é um **repositório local de assets reutilizáveis** empacotados com o OpalaCoder. Ela serve como banco de dados de casos bem-sucedidos de configuração para modelos locais e como biblioteca de skills extras que podem ser instaladas sob demanda em qualquer projeto.
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
opalacoder/assetstore/ ← instalado junto com o pacote pip
|
|
154
|
+
skills/
|
|
155
|
+
<ID>.zip ← árvore completa da skill
|
|
156
|
+
<ID>.metadata ← metadados YAML
|
|
157
|
+
modelconfigs/
|
|
158
|
+
<ID>.zip ← único arquivo .yaml de configuração
|
|
159
|
+
<ID>.metadata ← metadados YAML
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
O caminho base é sempre `Path(__file__).parent / "assetstore"`, portanto funciona corretamente quando instalado via `pip install opalacoder` em qualquer máquina.
|
|
163
|
+
|
|
164
|
+
### Formato dos metadados (`.metadata`)
|
|
165
|
+
|
|
166
|
+
Arquivo YAML com os campos:
|
|
167
|
+
|
|
168
|
+
| Campo | Obrigatório | Descrição |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `id` | ✓ | Identificador único do asset (ex: `skill_implement_feature`) |
|
|
171
|
+
| `type` | ✓ | `skill` ou `modelconfig` |
|
|
172
|
+
| `desc` | ✓ | Descrição legível usada como critério de busca |
|
|
173
|
+
| `name` | skill | Nome da skill (igual ao diretório dentro do zip) |
|
|
174
|
+
| `model` | modelconfig | Identificador do modelo (ex: `ollama/gpt-oss:latest`) |
|
|
175
|
+
|
|
176
|
+
**Exemplo — skill:**
|
|
177
|
+
```yaml
|
|
178
|
+
id: skill_implement_feature
|
|
179
|
+
type: skill
|
|
180
|
+
name: implement-feature
|
|
181
|
+
desc: Plan-Execute-Verify loop for implementing features and fixing bugs in project files
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Exemplo — modelconfig:**
|
|
185
|
+
```yaml
|
|
186
|
+
id: model_ollama_gpt_oss__latest
|
|
187
|
+
type: modelconfig
|
|
188
|
+
desc: gpt-oss:latest via Ollama — think=false, tool calling stable
|
|
189
|
+
model: ollama/gpt-oss:latest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Destino de instalação
|
|
193
|
+
|
|
194
|
+
| Tipo | Destino no projeto |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `skill` | `<projeto>/.opalacoder/skills/<name>/` |
|
|
197
|
+
| `modelconfig` | `<projeto>/.opalacoder/modelsconfig/<provider>/<modelo>.yaml` |
|
|
198
|
+
|
|
199
|
+
Para modelconfigs, o provider é normalizado: `ollama_chat/` e `ollama/` → diretório `ollama/`. Os dois pontos no nome do modelo viram `__`.
|
|
200
|
+
|
|
201
|
+
### Comandos REPL
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
/list_assets [tipo] — lista todos os assets (ou só do tipo especificado)
|
|
205
|
+
/load_asset <tipo> <desc|id|*> — instala asset(s) no projeto ativo
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`<desc>` pode ser o `id` exato ou o valor do campo `desc`. Usar `*` instala todos os assets do tipo.
|
|
209
|
+
|
|
210
|
+
**Exemplos:**
|
|
211
|
+
```
|
|
212
|
+
/list_assets
|
|
213
|
+
/list_assets modelconfig
|
|
214
|
+
/load_asset skill skill_implement_feature
|
|
215
|
+
/load_asset modelconfig model_ollama_gpt_oss__latest
|
|
216
|
+
/load_asset skill *
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Após instalar uma skill, ativá-la no projeto com `/addskill <name>`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 5.1. Banco de Configurações Refinadas de Modelos
|
|
224
|
+
|
|
225
|
+
> **Estado: IMPLEMENTADO**
|
|
226
|
+
|
|
227
|
+
### Conceito
|
|
228
|
+
|
|
229
|
+
O diretório `.opalacoder/modelsconfig/` dentro de cada projeto funciona como um
|
|
230
|
+
**banco de dados de casos bem-sucedidos de configuração para modelos locais**. Cada
|
|
231
|
+
arquivo YAML registra os parâmetros que produziram comportamento correto e estável
|
|
232
|
+
para um modelo específico naquele projeto — resultado de testes empíricos, não de
|
|
233
|
+
valores genéricos.
|
|
234
|
+
|
|
235
|
+
A motivação é que modelos locais (Ollama, LM Studio, etc.) exigem combinações
|
|
236
|
+
precisas de parâmetros para funcionar bem: `think` e `stream` podem quebrar
|
|
237
|
+
tool calling em certos modelos; `num_ctx` muito baixo degrada o raciocínio;
|
|
238
|
+
`temperature` alta pode destabilizar modelos de instrução. Esses parâmetros
|
|
239
|
+
**não são portáveis** — o que funciona para `deepseek-r1:14b` não funciona para
|
|
240
|
+
`ministral-3:14b`. O banco de configurações resolve isso por projeto.
|
|
241
|
+
|
|
242
|
+
### Estrutura de diretórios
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
<projeto>/
|
|
246
|
+
└── .opalacoder/
|
|
247
|
+
└── modelsconfig/
|
|
248
|
+
└── <provider>/
|
|
249
|
+
└── <nome_do_modelo>.yaml
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- **`<provider>`**: prefixo do modelo, com normalização — `ollama_chat/` e `ollama/`
|
|
253
|
+
mapeiam ambos para o diretório `ollama/`.
|
|
254
|
+
- **`<nome_do_modelo>.yaml`**: nome do modelo com `:` substituído por `__`
|
|
255
|
+
(hífens mantidos).
|
|
256
|
+
|
|
257
|
+
**Exemplos de mapeamento:**
|
|
258
|
+
|
|
259
|
+
| Modelo digitado | Diretório | Arquivo |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `ollama/deepseek-r1:14b` | `ollama/` | `deepseek-r1__14b.yaml` |
|
|
262
|
+
| `ollama_chat/deepseek-r1:14b` | `ollama/` | `deepseek-r1__14b.yaml` |
|
|
263
|
+
| `ollama/ministral-3:14b` | `ollama/` | `ministral-3__14b.yaml` |
|
|
264
|
+
| `ollama/qwen3:14b` | `ollama/` | `qwen3__14b.yaml` |
|
|
265
|
+
|
|
266
|
+
### Formato do arquivo YAML
|
|
267
|
+
|
|
268
|
+
O arquivo pode conter qualquer chave de `model_params` aceita pelo sistema, mais
|
|
269
|
+
uma chave especial `provider`:
|
|
270
|
+
|
|
271
|
+
```yaml
|
|
272
|
+
# .opalacoder/modelsconfig/ollama/deepseek-r1__14b.yaml
|
|
273
|
+
# Configuração refinada para DeepSeek-R1 14B via Ollama
|
|
274
|
+
# Obtida empiricamente — funciona com tool calling e thinking em tempo real
|
|
275
|
+
|
|
276
|
+
provider: ollama_chat # opcional: substitui o prefixo do modelo na sessão
|
|
277
|
+
# aqui muda de ollama/ para ollama_chat/ para habilitar
|
|
278
|
+
# o endpoint nativo do Ollama com thinking por chunk
|
|
279
|
+
|
|
280
|
+
# LiteLLM / model_kwargs
|
|
281
|
+
think: true
|
|
282
|
+
stream: true
|
|
283
|
+
temperature: 0.6
|
|
284
|
+
num_ctx: 32768
|
|
285
|
+
max_tokens: 8192
|
|
286
|
+
|
|
287
|
+
# Parâmetros do agente
|
|
288
|
+
max_heartbeats: 15
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
# .opalacoder/modelsconfig/ollama/ministral-3__14b.yaml
|
|
293
|
+
# Ministral 3 14B — sem thinking (não suportado), tool calling estável
|
|
294
|
+
|
|
295
|
+
think: false
|
|
296
|
+
stream: false
|
|
297
|
+
temperature: 0.7
|
|
298
|
+
num_ctx: 16384
|
|
299
|
+
max_tokens: 8128
|
|
300
|
+
max_heartbeats: 20
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Chave `provider`** (opcional): quando presente, substitui o prefixo do modelo
|
|
304
|
+
na interface. Útil para forçar `ollama_chat/` em modelos com suporte a thinking
|
|
305
|
+
nativo, sem o usuário precisar digitar o prefixo correto.
|
|
306
|
+
|
|
307
|
+
### Como usar
|
|
308
|
+
|
|
309
|
+
Na janela de **criação** ou **configuração** de projeto, após definir o modelo,
|
|
310
|
+
clique em **Load Refined Config**:
|
|
311
|
+
|
|
312
|
+
- Se existir um arquivo para o modelo: carrega e substitui completamente o
|
|
313
|
+
`model_params` do projeto. Se o YAML tiver `provider:`, atualiza o campo
|
|
314
|
+
modelo com o novo prefixo.
|
|
315
|
+
- Se não existir: exibe `--- ainda não temos parâmetros refinados para este modelo`.
|
|
316
|
+
|
|
317
|
+
O backend resolve o arquivo via `GET/POST /api/opalacoder/model-config`
|
|
318
|
+
([ide_server.py](../../opalacoder/ide_server.py)).
|
|
319
|
+
|
|
320
|
+
### Critério para adicionar uma entrada
|
|
321
|
+
|
|
322
|
+
Uma entrada deve ser adicionada ao banco quando:
|
|
323
|
+
|
|
324
|
+
1. O modelo foi testado com a configuração e **tool calling funciona** sem erros.
|
|
325
|
+
2. O comportamento de **thinking/reflection** (se aplicável) está correto.
|
|
326
|
+
3. Os valores de **contexto e tokens** são adequados ao hardware disponível.
|
|
327
|
+
|
|
328
|
+
O arquivo é mantido manualmente pelo usuário/equipe e versionado junto com o
|
|
329
|
+
projeto. Não é gerado automaticamente.
|
|
330
|
+
|
|
331
|
+
### Exemplo completo — `gpt-oss:latest` (Ollama)
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
# .opalacoder/modelsconfig/ollama/gpt-oss__latest.yaml
|
|
335
|
+
#
|
|
336
|
+
# Configuração refinada para gpt-oss:latest via Ollama
|
|
337
|
+
# Testado em: 2026-06-02 | Hardware: RTX 4090 24GB
|
|
338
|
+
# Status: tool calling OK, thinking OK, stream OK
|
|
339
|
+
#
|
|
340
|
+
provider: ollama_chat # endpoint nativo: thinking por chunk em tempo real
|
|
341
|
+
|
|
342
|
+
# LiteLLM / model_kwargs
|
|
343
|
+
think: false # desativar thinking evita bug de tool_calls vazio (ollama #15288)
|
|
344
|
+
stream: false # stream false: mais estável com tool calling
|
|
345
|
+
temperature: 0.1 # baixo para respostas determinísticas em tarefas de código
|
|
346
|
+
num_ctx: 32768 # contexto amplo para projetos grandes
|
|
347
|
+
max_tokens: 8192
|
|
348
|
+
|
|
349
|
+
# Parâmetros do agente MemGPT (chat-orquestrador)
|
|
350
|
+
max_heartbeats: 20
|
|
351
|
+
max_context_tokens: 32768
|
|
352
|
+
|
|
353
|
+
# Parâmetros do agente LLMAgentBlock (workers)
|
|
354
|
+
max_tool_calls: 10
|
|
355
|
+
debug: false
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## 6. Comandos do REPL
|
|
145
361
|
|
|
146
362
|
Registrados em [cli_commands.py](../../opalacoder/cli_commands.py):
|
|
147
363
|
|
|
@@ -75,6 +75,7 @@ export default function App() {
|
|
|
75
75
|
const [thinkingLogs, setThinkingLogs] = useState([]);
|
|
76
76
|
const [showAdvancedParams, setShowAdvancedParams] = useState(false);
|
|
77
77
|
const [newProjError, setNewProjError] = useState('');
|
|
78
|
+
const [modelConfigMsg, setModelConfigMsg] = useState('');
|
|
78
79
|
|
|
79
80
|
// Directory picker state: { target: 'new'|'edit', current: '/path', dirs: [{name,path}] } | null
|
|
80
81
|
const [dirPicker, setDirPicker] = useState(null);
|
|
@@ -182,6 +183,7 @@ export default function App() {
|
|
|
182
183
|
const [newProjDesc, setNewProjDesc] = useState('');
|
|
183
184
|
const [newProjModel, setNewProjModel] = useState('gemini/gemini-2.5-flash');
|
|
184
185
|
const [newProjMode, setNewProjMode] = useState('auto');
|
|
186
|
+
const [newProjModelParams, setNewProjModelParams] = useState({});
|
|
185
187
|
const [newProjApiKey, setNewProjApiKey] = useState('');
|
|
186
188
|
const [newProjApiBase, setNewProjApiBase] = useState('http://localhost:11434/v1');
|
|
187
189
|
|
|
@@ -440,6 +442,18 @@ export default function App() {
|
|
|
440
442
|
}
|
|
441
443
|
}, [activeProject]);
|
|
442
444
|
|
|
445
|
+
// Polling for workspace file changes and git status (every 10 seconds)
|
|
446
|
+
useEffect(() => {
|
|
447
|
+
if (!activeProject) return;
|
|
448
|
+
|
|
449
|
+
const interval = setInterval(() => {
|
|
450
|
+
fetchFiles();
|
|
451
|
+
fetchGitStatus();
|
|
452
|
+
}, 10000);
|
|
453
|
+
|
|
454
|
+
return () => clearInterval(interval);
|
|
455
|
+
}, [activeProject]);
|
|
456
|
+
|
|
443
457
|
useEffect(() => {
|
|
444
458
|
if (activeSidebarTab === 'git' && activeProject) {
|
|
445
459
|
fetchGitStatus();
|
|
@@ -980,7 +994,8 @@ export default function App() {
|
|
|
980
994
|
model: newProjModel,
|
|
981
995
|
mode: newProjMode,
|
|
982
996
|
api_key: newProjApiKey,
|
|
983
|
-
api_base: newProjApiBase
|
|
997
|
+
api_base: newProjApiBase,
|
|
998
|
+
model_params: Object.keys(newProjModelParams).length ? newProjModelParams : undefined
|
|
984
999
|
})
|
|
985
1000
|
});
|
|
986
1001
|
if (res.ok) {
|
|
@@ -1035,6 +1050,7 @@ export default function App() {
|
|
|
1035
1050
|
if (found) fresh = found;
|
|
1036
1051
|
}
|
|
1037
1052
|
} catch (_) { }
|
|
1053
|
+
setModelConfigMsg('');
|
|
1038
1054
|
setEditingProject({
|
|
1039
1055
|
name: fresh.name,
|
|
1040
1056
|
project_name: fresh.project_name || fresh.name,
|
|
@@ -1087,6 +1103,30 @@ export default function App() {
|
|
|
1087
1103
|
}
|
|
1088
1104
|
};
|
|
1089
1105
|
|
|
1106
|
+
const loadModelConfig = async (projectPath, model, applyFn) => {
|
|
1107
|
+
setModelConfigMsg('');
|
|
1108
|
+
if (!projectPath || !model) {
|
|
1109
|
+
setModelConfigMsg('⚠️ Defina o caminho do projeto e o modelo antes de carregar.');
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
try {
|
|
1113
|
+
const res = await fetch('/api/opalacoder/model-config', {
|
|
1114
|
+
method: 'POST',
|
|
1115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1116
|
+
body: JSON.stringify({ projectPath, model }),
|
|
1117
|
+
});
|
|
1118
|
+
const data = await res.json();
|
|
1119
|
+
if (!data.found) {
|
|
1120
|
+
setModelConfigMsg(data.message);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
applyFn(data);
|
|
1124
|
+
setModelConfigMsg('✅ Configuração refinada carregada.');
|
|
1125
|
+
} catch (e) {
|
|
1126
|
+
setModelConfigMsg(`⚠️ Erro ao carregar: ${e.message}`);
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1090
1130
|
const openDirPicker = async (target, startPath) => {
|
|
1091
1131
|
const path = startPath || '~';
|
|
1092
1132
|
try {
|
|
@@ -1194,6 +1234,7 @@ export default function App() {
|
|
|
1194
1234
|
setChatMessages(prev => [...prev, { role: 'assistant', content: `🔴 Falha: ${err.message}` }]);
|
|
1195
1235
|
} finally {
|
|
1196
1236
|
setIsAgentRunning(false);
|
|
1237
|
+
fetchFiles();
|
|
1197
1238
|
}
|
|
1198
1239
|
return;
|
|
1199
1240
|
}
|
|
@@ -1474,7 +1515,7 @@ export default function App() {
|
|
|
1474
1515
|
<div className="vscode-sidebar-header">
|
|
1475
1516
|
<span className="vscode-sidebar-title">EXPLORER: PROJECTS</span>
|
|
1476
1517
|
<button
|
|
1477
|
-
onClick={() => setShowNewProjectModal(true)}
|
|
1518
|
+
onClick={() => { setShowNewProjectModal(true); setModelConfigMsg(''); setNewProjModelParams({}); }}
|
|
1478
1519
|
style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: '#c5c5c5' }}
|
|
1479
1520
|
title="Novo Projeto..."
|
|
1480
1521
|
>
|
|
@@ -1545,7 +1586,39 @@ export default function App() {
|
|
|
1545
1586
|
}}
|
|
1546
1587
|
style={dragOverPath === '__root__' ? { border: '2px dashed #007acc', backgroundColor: 'rgba(0, 122, 204, 0.05)' } : {}}
|
|
1547
1588
|
>
|
|
1548
|
-
<div className="vscode-sidebar-section-title"
|
|
1589
|
+
<div className="vscode-sidebar-section-title" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
1590
|
+
<span>Workspace Files</span>
|
|
1591
|
+
{activeProject && (
|
|
1592
|
+
<button
|
|
1593
|
+
onClick={(e) => {
|
|
1594
|
+
e.stopPropagation();
|
|
1595
|
+
fetchFiles();
|
|
1596
|
+
}}
|
|
1597
|
+
title="Atualizar arquivos"
|
|
1598
|
+
style={{
|
|
1599
|
+
background: 'transparent',
|
|
1600
|
+
border: 'none',
|
|
1601
|
+
color: '#808080',
|
|
1602
|
+
cursor: 'pointer',
|
|
1603
|
+
display: 'flex',
|
|
1604
|
+
alignItems: 'center',
|
|
1605
|
+
padding: '2px',
|
|
1606
|
+
borderRadius: '3px',
|
|
1607
|
+
transition: 'color 0.2s, background-color 0.2s',
|
|
1608
|
+
}}
|
|
1609
|
+
onMouseOver={(e) => {
|
|
1610
|
+
e.currentTarget.style.color = '#ffffff';
|
|
1611
|
+
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
|
|
1612
|
+
}}
|
|
1613
|
+
onMouseOut={(e) => {
|
|
1614
|
+
e.currentTarget.style.color = '#808080';
|
|
1615
|
+
e.currentTarget.style.backgroundColor = 'transparent';
|
|
1616
|
+
}}
|
|
1617
|
+
>
|
|
1618
|
+
<RefreshCw size={12} />
|
|
1619
|
+
</button>
|
|
1620
|
+
)}
|
|
1621
|
+
</div>
|
|
1549
1622
|
{files.length === 0 ? (
|
|
1550
1623
|
<div style={{ fontSize: '12px', color: '#808080', padding: '0 4px', fontStyle: 'italic' }}>
|
|
1551
1624
|
Selecione um projeto para explorar.
|
|
@@ -2194,6 +2267,22 @@ export default function App() {
|
|
|
2194
2267
|
</div>
|
|
2195
2268
|
</div>
|
|
2196
2269
|
|
|
2270
|
+
{/* Load refined model config */}
|
|
2271
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
|
|
2272
|
+
<button type="button" className="vscode-button" style={{ background: '#3c3c3c', fontSize: '12px' }}
|
|
2273
|
+
onClick={() => loadModelConfig(newProjPath, newProjModel, (cfg) => {
|
|
2274
|
+
if (cfg.model_params) setNewProjModelParams(cfg.model_params);
|
|
2275
|
+
if (cfg.model) setNewProjModel(cfg.model);
|
|
2276
|
+
})}>
|
|
2277
|
+
Load Refined Config
|
|
2278
|
+
</button>
|
|
2279
|
+
{modelConfigMsg && (
|
|
2280
|
+
<span style={{ fontSize: '11px', color: modelConfigMsg.startsWith('✅') ? '#4ec9b0' : '#f48771' }}>
|
|
2281
|
+
{modelConfigMsg}
|
|
2282
|
+
</span>
|
|
2283
|
+
)}
|
|
2284
|
+
</div>
|
|
2285
|
+
|
|
2197
2286
|
{newProjError && (
|
|
2198
2287
|
<div style={{ color: '#f48771', fontSize: '11px', marginTop: '4px', whiteSpace: 'pre-wrap' }}>
|
|
2199
2288
|
⚠️ {newProjError}
|
|
@@ -2359,6 +2448,25 @@ export default function App() {
|
|
|
2359
2448
|
</div>
|
|
2360
2449
|
</div>
|
|
2361
2450
|
|
|
2451
|
+
{/* Load refined model config */}
|
|
2452
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
|
|
2453
|
+
<button type="button" className="vscode-button" style={{ background: '#3c3c3c', fontSize: '12px' }}
|
|
2454
|
+
onClick={() => loadModelConfig(editingProject.project_path, editingProject.model, (cfg) => {
|
|
2455
|
+
setEditingProject(p => ({
|
|
2456
|
+
...p,
|
|
2457
|
+
model_params: cfg.model_params || p.model_params,
|
|
2458
|
+
model: cfg.model || p.model,
|
|
2459
|
+
}));
|
|
2460
|
+
})}>
|
|
2461
|
+
Load Refined Config
|
|
2462
|
+
</button>
|
|
2463
|
+
{modelConfigMsg && (
|
|
2464
|
+
<span style={{ fontSize: '11px', color: modelConfigMsg.startsWith('✅') ? '#4ec9b0' : '#f48771' }}>
|
|
2465
|
+
{modelConfigMsg}
|
|
2466
|
+
</span>
|
|
2467
|
+
)}
|
|
2468
|
+
</div>
|
|
2469
|
+
|
|
2362
2470
|
{/* Alternative model */}
|
|
2363
2471
|
<div className="flex flex-col" style={{ gap: '4px' }}>
|
|
2364
2472
|
<label className="vscode-sidebar-section-title" style={{ padding: 0 }}>Modelo Alternativo</label>
|
|
@@ -92,6 +92,11 @@ input, select, textarea {
|
|
|
92
92
|
outline: none;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
select option {
|
|
96
|
+
background-color: var(--vscode-input-bg);
|
|
97
|
+
color: var(--vscode-text-fg);
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
input:focus, select:focus, textarea:focus {
|
|
96
101
|
border-color: var(--vscode-active-border);
|
|
97
102
|
}
|
|
Binary file
|
|
@@ -286,11 +286,22 @@ async def handle_slash_command(data: dict) -> dict:
|
|
|
286
286
|
T.confirm = lambda p, default=True: default # sync fallback never used in GUI
|
|
287
287
|
T.ask = lambda p: ""
|
|
288
288
|
|
|
289
|
+
def _render_rich(obj) -> str:
|
|
290
|
+
from rich.console import Console as _Console
|
|
291
|
+
from rich.table import Table as _Table
|
|
292
|
+
from io import StringIO
|
|
293
|
+
if isinstance(obj, _Table):
|
|
294
|
+
buf = StringIO()
|
|
295
|
+
c = _Console(file=buf, highlight=False, no_color=True)
|
|
296
|
+
c.print(obj)
|
|
297
|
+
return buf.getvalue()
|
|
298
|
+
return str(obj)
|
|
299
|
+
|
|
289
300
|
def _console_print(*args_c, **kwargs_c):
|
|
290
301
|
if not args_c:
|
|
291
302
|
messages.append("")
|
|
292
303
|
return
|
|
293
|
-
raw = " ".join(
|
|
304
|
+
raw = " ".join(_render_rich(x) for x in args_c)
|
|
294
305
|
for line in raw.split("\n"):
|
|
295
306
|
stripped = line.strip()
|
|
296
307
|
if not stripped:
|
|
@@ -302,6 +313,9 @@ async def handle_slash_command(data: dict) -> dict:
|
|
|
302
313
|
messages.append("### 🧠 Active skills for this project\n"); continue
|
|
303
314
|
if "Available skills" in stripped:
|
|
304
315
|
messages.append("### 📚 Available skills\n"); continue
|
|
316
|
+
clean = re.sub(r'\[/?[\w\s]+\]', '', stripped)
|
|
317
|
+
if clean and clean == clean.upper() and clean.replace(" ", "").isalpha():
|
|
318
|
+
messages.append(f"### {clean}\n"); continue
|
|
305
319
|
m = re.match(r'\s*(?:\*\s*)?\[(green|cyan)\]\s*(.*?)\s*\[/\1\]\s*(.*)', line)
|
|
306
320
|
if m:
|
|
307
321
|
name = m.group(2).strip()
|
|
@@ -316,7 +330,7 @@ async def handle_slash_command(data: dict) -> dict:
|
|
|
316
330
|
if sm:
|
|
317
331
|
star = "⭐ " if has_star else "🔹 "
|
|
318
332
|
messages.append(f"{star}**`{sm.group(1).strip()}`** — {sm.group(2).strip()}"); continue
|
|
319
|
-
messages.append(re.sub(r'\[
|
|
333
|
+
messages.append(re.sub(r'\[/?[\w\s]+\]', '', line))
|
|
320
334
|
|
|
321
335
|
T.console.print = _console_print
|
|
322
336
|
|
|
Binary file
|
|
Binary file
|