Skip to content

Commit f67ef71

Browse files
committed
LLM: Support Using Environment Vairables in Config.
The main changes include: * **Environment handling**: Introduced a new `EnvSetter` default constructor that automatically applies environment variables from the active workspace (either FileSystemWorkspace or CxxWorkspace), eliminating the need for manual environment setup in various locations. * **API improvements**: Made `EnvSetter` class exportable (`WXDLLIMPEXP_SDK`) and added `ToEnvList()` method to `EnvMap` for converting to the standard environment list format. * **Tool execution**: Updated AI tool shell execution and LLM manager to use the new automatic environment setup, ensuring consistent environment application. * **Error handling protocol**: Refined the system message for AI error handling to be more concise and clearer about the three-attempt maximum rule. ** Generated by CodeLite. ** Signed-off-by: Eran Ifrah <eran@codelite.org>
1 parent 6b59484 commit f67ef71

File tree

10 files changed

+99
-53
lines changed

10 files changed

+99
-53
lines changed

CodeLite/clEnvironment.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ using clEnvList_t = std::vector<std::pair<wxString, wxString>>;
1111

1212
class WXDLLIMPEXP_CL clEnvironment
1313
{
14-
const clEnvList_t* m_env = nullptr;
15-
std::vector<std::pair<wxString, wxAny>> m_old_env;
16-
17-
private:
18-
void ApplyFromList(const clEnvList_t* envlist);
19-
2014
public:
2115
clEnvironment(const clEnvList_t* envlist);
2216
clEnvironment();
2317
virtual ~clEnvironment();
18+
19+
void ApplyFromList(const clEnvList_t* envlist);
20+
21+
private:
22+
const clEnvList_t* m_env = nullptr;
23+
std::vector<std::pair<wxString, wxAny>> m_old_env;
2424
};
2525

2626
#endif // CLENVIRONMENT_HPP

Plugin/ai/LLMManager.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "cl_command_event.h"
1010
#include "cl_standard_paths.h"
1111
#include "codelite_events.h"
12+
#include "environmentconfig.h"
1213
#include "event_notifier.h"
1314
#include "file_logger.h"
1415
#include "fileextmanager.h"
@@ -32,10 +33,8 @@ When encountering errors:
3233
3334
1. **First error:** Analyze, attempt one fix, retry once
3435
2. **Second error (same type):** Try one alternative approach if available
35-
3. **Third error or no clear alternative:** **STOP. Report the issue and all attempts made. Ask user for guidance.**
36-
36+
3. **Third error:** **STOP**. Report the issue. Ask user for guidance.**
3737
Apply to: permission denied, tool failures, file errors, invalid parameters, command failures.
38-
3938
**Never** loop indefinitely on repeated failures. Three attempts maximum before escalating to user.)#";
4039

4140
/**
@@ -557,9 +556,9 @@ assistant::Config Manager::MakeConfig()
557556
return m_default_config;
558557
}
559558

560-
assistant::Config config =
561-
assistant::Config::FromFile(res.value().ToStdString(wxConvUTF8)).value_or(m_default_config);
562-
return config;
559+
// Apply environment variables before we proceed
560+
EnvSetter env;
561+
return assistant::Config::FromFile(res.value().ToStdString(wxConvUTF8)).value_or(m_default_config);
563562
}
564563

565564
void Manager::Restart()
@@ -651,6 +650,7 @@ void Manager::Start(std::shared_ptr<assistant::ClientBase> client)
651650

652651
m_client->SetCachingPolicy(GetConfig().GetCachePolicy());
653652
m_client->SetTookInvokeCallback(&Manager::CanRunTool);
653+
m_client->ClearSystemMessages();
654654
m_client->AddSystemMessage(kSystemMessageRetryProtocol);
655655

656656
// Start the worker thread
@@ -681,6 +681,7 @@ bool Manager::ReloadConfig(std::optional<wxString> config_content, bool prompt)
681681
content = FileManager::ReadSettingsFileContent(kAssistantConfigFile, opts).value_or(kDefaultSettings);
682682
}
683683

684+
EnvSetter env;
684685
auto conf = assistant::Config::FromContent(content.ToStdString(wxConvUTF8));
685686
if (conf.has_value()) {
686687
m_client_config = std::move(conf.value());
@@ -973,6 +974,7 @@ clStatusOr<wxString> Manager::CreateOrOpenConfig()
973974
wxString backup_file_path = global_config_path + ".old";
974975
bool valid_file{false};
975976
try {
977+
EnvSetter env;
976978
auto conf = assistant::Config::FromFile(global_config_path.ToStdString(wxConvUTF8));
977979
valid_file = conf.has_value();
978980
} catch (const std::exception& e) {

Plugin/ai/Tools.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clSFTPManager.hpp"
1212
#include "clWorkspaceManager.h"
1313
#include "codelite_events.h"
14+
#include "environmentconfig.h"
1415
#include "event_notifier.h"
1516
#include "globals.h"
1617
#include "procutils.h"
@@ -506,6 +507,7 @@ FunctionResult ToolShellExecute([[maybe_unused]] const assistant::json& args)
506507
// Local command.
507508
ProcUtils::WrapInShell(cmd);
508509
wxArrayString output_arr;
510+
EnvSetter env;
509511
ProcUtils::SafeExecuteCommand(cmd, output_arr, termination_flag.GetFlag());
510512
if (termination_flag.IsSet()) {
511513
return FunctionResult{.isError = true, .text = "Command terminated by user"};
@@ -519,6 +521,7 @@ FunctionResult ToolShellExecute([[maybe_unused]] const assistant::json& args)
519521
// Local command.
520522
ProcUtils::WrapInShell(cmd);
521523
wxArrayString output_arr;
524+
EnvSetter env;
522525
ProcUtils::SafeExecuteCommand(cmd, output_arr, termination_flag.GetFlag());
523526
llm::Manager::GetInstance().DeleteTerminationFlag(termination_flag.GetFlag());
524527
if (termination_flag.IsSet()) {
@@ -530,6 +533,7 @@ FunctionResult ToolShellExecute([[maybe_unused]] const assistant::json& args)
530533
func_result.isError = false;
531534
func_result.text = command_output;
532535
#endif
536+
533537
llm::Manager::GetInstance().PrintMessage(
534538
_("Successfully executed the command. Output:\n```bash\n") + func_result.text + "\n```\n", IconType::kInfo);
535539
return func_result;
@@ -540,17 +544,14 @@ FunctionResult GetOS([[maybe_unused]] const assistant::json& args)
540544
VERIFY_WORKER_THREAD();
541545

542546
// Check if a remote workspace is opened - if so, always return "Linux"
543-
auto cb = [=]() -> FunctionResult {
547+
auto is_remote_workspace_cb = [=]() -> bool {
544548
auto workspace = clWorkspaceManager::Get().GetWorkspace();
545-
if (workspace && workspace->IsRemote()) {
546-
return Ok(wxString("Linux"));
547-
}
548-
return FunctionResult{.isError = false}; // Signal to continue with local OS detection
549+
return workspace && workspace->IsRemote();
549550
};
550551

551-
auto result = EventNotifier::Get()->RunOnMain<FunctionResult>(std::move(cb));
552-
if (!result.text.empty()) {
553-
return result; // Remote workspace detected, return "Linux"
552+
auto is_remote = EventNotifier::Get()->RunOnMain<bool>(std::move(is_remote_workspace_cb));
553+
if (is_remote) {
554+
return Ok("Linux"); // Remote workspace detected, return "Linux"
554555
}
555556

556557
wxString os_name;

Plugin/environmentconfig.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
//////////////////////////////////////////////////////////////////////////////
2525
#include "environmentconfig.h"
2626

27+
#include "FileSystemWorkspace/clFileSystemWorkspace.hpp"
2728
#include "archive.h"
2829
#include "envvarlist.h"
2930
#include "macromanager.h"
31+
#include "workspace.h"
3032
#include "xmlutils.h"
3133

3234
#include <algorithm>
@@ -272,3 +274,24 @@ DollarEscaper::~DollarEscaper()
272274
// we restore it to non escaped $ !!
273275
m_str.Replace("@@ESC_DOLLAR@@", "$");
274276
}
277+
278+
// EnvSetter
279+
280+
EnvSetter::EnvSetter()
281+
: m_env(EnvironmentConfig::Instance())
282+
{
283+
wxStringMap_t env_map;
284+
wxString project_name, config_name;
285+
if (clFileSystemWorkspace::Get().IsOpen() && !clFileSystemWorkspace::Get().IsRemote()) {
286+
auto env_list = clFileSystemWorkspace::Get().GetEnvironment();
287+
for (const auto& [k, v] : env_list) {
288+
env_map.insert({k, v});
289+
}
290+
291+
} else if (clCxxWorkspaceST::Get()->IsOpen() && clCxxWorkspaceST::Get()->GetActiveProject()) {
292+
auto project = clCxxWorkspaceST::Get()->GetActiveProject();
293+
config_name = project->GetBuildConfiguration() ? project->GetBuildConfiguration()->GetName() : wxString{};
294+
project_name = project->GetName();
295+
}
296+
m_env->ApplyEnv(&env_map, project_name, config_name);
297+
}

Plugin/environmentconfig.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,11 @@ class WXDLLIMPEXP_SDK EnvironmentConfig : public ConfigurationToolBase
8484
virtual wxString GetRootName();
8585
};
8686

87-
class EnvSetter
87+
class WXDLLIMPEXP_SDK EnvSetter
8888
{
8989
public:
90-
explicit EnvSetter(wxStringMap_t* om = NULL)
90+
EnvSetter();
91+
explicit EnvSetter(wxStringMap_t* om)
9192
: m_env(EnvironmentConfig::Instance())
9293
{
9394
m_env->ApplyEnv(om, wxEmptyString, wxEmptyString);
@@ -101,7 +102,7 @@ class EnvSetter
101102
if (envlist) {
102103
overrideMap.reserve(envlist->size());
103104
for (const auto& [name, value] : *envlist) {
104-
overrideMap.insert({ name, value });
105+
overrideMap.insert({name, value});
105106
}
106107
}
107108
m_env->ApplyEnv(&overrideMap, wxEmptyString, wxEmptyString);

Plugin/envvarlist.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ void EnvVarList::AddVariable(const wxString& setName, const wxString& name, cons
5555
wxString currentValueStr = DoGetSetVariablesStr(setName, actualSetName);
5656
wxArrayString currentValues = wxStringTokenize(currentValueStr, wxT("\r\n"), wxTOKEN_STRTOK);
5757

58-
if(currentValues.Index(newEntry) == wxNOT_FOUND)
58+
if (currentValues.Index(newEntry) == wxNOT_FOUND)
5959
currentValues.Add(newEntry);
6060

6161
currentValueStr.Clear();
62-
for(size_t i = 0; i < currentValues.GetCount(); i++) {
62+
for (size_t i = 0; i < currentValues.GetCount(); i++) {
6363
currentValueStr << currentValues.Item(i) << wxT("\n");
6464
}
6565

66-
if(currentValueStr.IsEmpty() == false)
66+
if (currentValueStr.IsEmpty() == false)
6767
currentValueStr.RemoveLast();
6868

6969
m_envVarSets[actualSetName] = currentValueStr;
@@ -76,47 +76,49 @@ void EnvVarList::InsertVariable(const wxString& setName, const wxString& name, c
7676
DoGetSetVariablesStr(setName, actualSetName);
7777

7878
EnvMap set = GetVariables(actualSetName, false, wxEmptyString, wxEmptyString);
79-
if(!set.Contains(name)) {
79+
if (!set.Contains(name)) {
8080
set.Put(name, value);
8181
}
8282
m_envVarSets[actualSetName] = set.String();
8383
}
8484

85-
EnvMap EnvVarList::GetVariables(const wxString& setName, bool includeWorkspaceEnvs, const wxString& projectName,
85+
EnvMap EnvVarList::GetVariables(const wxString& setName,
86+
bool includeWorkspaceEnvs,
87+
const wxString& projectName,
8688
const wxString& configName)
8789
{
8890
EnvMap variables;
8991
wxString actualSetName;
9092

9193
wxString currentValueStr = DoGetSetVariablesStr(setName, actualSetName);
9294

93-
if(includeWorkspaceEnvs && !clCxxWorkspaceST::Get()->GetName().IsEmpty()) {
95+
if (includeWorkspaceEnvs && !clCxxWorkspaceST::Get()->GetName().IsEmpty()) {
9496
currentValueStr.Trim().Trim(false);
9597
currentValueStr << wxT("\n");
9698
currentValueStr << clCxxWorkspaceST::Get()->GetEnvironmentVariables();
9799

98-
if(projectName.IsEmpty() == false) {
100+
if (projectName.IsEmpty() == false) {
99101
currentValueStr.Trim().Trim(false);
100102
BuildConfigPtr buildConf = clCxxWorkspaceST::Get()->GetProjBuildConf(projectName, configName);
101-
if(buildConf) {
103+
if (buildConf) {
102104
currentValueStr << wxT("\n");
103105
currentValueStr << buildConf->GetEnvvars();
104106
}
105107
}
106108
}
107109

108110
wxArrayString currentValues = wxStringTokenize(currentValueStr, wxT("\r\n"), wxTOKEN_STRTOK);
109-
for(size_t i = 0; i < currentValues.GetCount(); i++) {
111+
for (size_t i = 0; i < currentValues.GetCount(); i++) {
110112
wxString entry = currentValues.Item(i);
111113

112114
// remove any comment from the line
113115
int where = entry.Find(wxT("#"));
114-
if(where != wxNOT_FOUND) {
116+
if (where != wxNOT_FOUND) {
115117
entry = entry.Left(where);
116118
}
117119

118120
entry.Trim().Trim(false);
119-
if(entry.IsEmpty()) {
121+
if (entry.IsEmpty()) {
120122
continue;
121123
}
122124

@@ -136,17 +138,17 @@ wxString EnvVarList::DoGetSetVariablesStr(const wxString& setName, wxString& sel
136138

137139
selectedSetName = setName;
138140
wxStringMap_t::iterator iter = m_envVarSets.find(setName);
139-
if(iter != m_envVarSets.end())
141+
if (iter != m_envVarSets.end())
140142
currentValueStr = iter->second;
141143
else {
142144
iter = m_envVarSets.find(m_activeSet);
143-
if(iter != m_envVarSets.end()) {
145+
if (iter != m_envVarSets.end()) {
144146
currentValueStr = iter->second;
145147
selectedSetName = m_activeSet;
146148
} else {
147149
selectedSetName = wxT("Default");
148150
iter = m_envVarSets.find(selectedSetName);
149-
if(iter != m_envVarSets.end())
151+
if (iter != m_envVarSets.end())
150152
currentValueStr = iter->second;
151153
}
152154
}
@@ -160,7 +162,7 @@ bool EnvVarList::IsSetExist(const wxString& setName) { return m_envVarSets.find(
160162
bool EnvMap::Get(const wxString& key, wxString& val)
161163
{
162164
int where = m_keys.Index(key);
163-
if(where == wxNOT_FOUND)
165+
if (where == wxNOT_FOUND)
164166
return false;
165167

166168
val = m_values.Item(where);
@@ -184,7 +186,7 @@ size_t EnvMap::GetCount() { return m_keys.GetCount(); }
184186

185187
bool EnvMap::Get(size_t index, wxString& key, wxString& val)
186188
{
187-
if(index >= m_keys.GetCount())
189+
if (index >= m_keys.GetCount())
188190
return false;
189191

190192
key = m_keys.Item(index);
@@ -197,11 +199,11 @@ bool EnvMap::Contains(const wxString& key) { return m_keys.Index(key) != wxNOT_F
197199
wxString EnvMap::String()
198200
{
199201
wxString s;
200-
for(size_t i = 0; i < m_keys.GetCount(); i++) {
202+
for (size_t i = 0; i < m_keys.GetCount(); i++) {
201203
s << m_keys.Item(i) << wxT("=") << m_values.Item(i) << wxT("\n");
202204
}
203205

204-
if(s.IsEmpty() == false)
206+
if (s.IsEmpty() == false)
205207
s.RemoveLast();
206208

207209
return s;

Plugin/envvarlist.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#ifndef __evnvarlist__
2626
#define __evnvarlist__
2727

28+
#include "clEnvironment.hpp"
2829
#include "codelite_exports.h"
2930
#include "macros.h"
3031
#include "serialized_object.h"
@@ -33,8 +34,6 @@
3334

3435
class WXDLLIMPEXP_SDK EnvMap
3536
{
36-
wxArrayString m_keys;
37-
wxArrayString m_values;
3837

3938
public:
4039
EnvMap() = default;
@@ -47,6 +46,23 @@ class WXDLLIMPEXP_SDK EnvMap
4746
bool Get(size_t index, wxString& key, wxString& val);
4847
bool Contains(const wxString& key);
4948
wxString String();
49+
50+
inline clEnvList_t ToEnvList() const
51+
{
52+
clEnvList_t result;
53+
if (m_keys.size() != m_values.size()) {
54+
return result;
55+
}
56+
result.reserve(m_keys.size());
57+
for (size_t i = 0; i < m_keys.size(); ++i) {
58+
result.push_back({m_keys[i].ToStdString(wxConvUTF8), m_values[i].ToStdString(wxConvUTF8)});
59+
}
60+
return result;
61+
}
62+
63+
private:
64+
wxArrayString m_keys;
65+
wxArrayString m_values;
5066
};
5167

5268
class WXDLLIMPEXP_SDK EnvVarList : public SerializedObject
@@ -63,7 +79,7 @@ class WXDLLIMPEXP_SDK EnvVarList : public SerializedObject
6379

6480
void SetActiveSet(const wxString& activeSet)
6581
{
66-
if(activeSet != _("<Use Active Set>") && activeSet != USE_GLOBAL_SETTINGS)
82+
if (activeSet != _("<Use Active Set>") && activeSet != USE_GLOBAL_SETTINGS)
6783
this->m_activeSet = activeSet;
6884
}
6985

@@ -81,7 +97,9 @@ class WXDLLIMPEXP_SDK EnvVarList : public SerializedObject
8197
*/
8298
void InsertVariable(const wxString& setName, const wxString& name, const wxString& value);
8399

84-
EnvMap GetVariables(const wxString& setName, bool includeWorkspaceEnvs, const wxString& projectName,
100+
EnvMap GetVariables(const wxString& setName,
101+
bool includeWorkspaceEnvs,
102+
const wxString& projectName,
85103
const wxString& configName);
86104
bool IsSetExist(const wxString& setName);
87105

0 commit comments

Comments
 (0)