mindroot 8.9.0__py3-none-any.whl → 8.11.0__py3-none-any.whl

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.

Potentially problematic release.


This version of mindroot might be problematic. Click here for more details.

Files changed (27) hide show
  1. mindroot/coreplugins/admin/plugin_manager.py +21 -3
  2. mindroot/coreplugins/admin/static/js/agent-form.js +38 -22
  3. mindroot/coreplugins/admin/static/js/plugin-advanced-install.js +8 -0
  4. mindroot/coreplugins/agent/templates/system.jinja2 +18 -0
  5. mindroot/coreplugins/chat/commands.py +11 -2
  6. mindroot/coreplugins/chat/router.py +48 -1
  7. mindroot/coreplugins/chat/services.py +4 -2
  8. mindroot/coreplugins/index/default.json +21 -15
  9. mindroot/coreplugins/index/handlers/plugin_ops.py +13 -0
  10. mindroot/coreplugins/index/indices/default/index.json +9 -6
  11. mindroot/coreplugins/index/static/js/plugin-section.js +42 -5
  12. mindroot/coreplugins/login/templates/login.jinja2 +4 -1
  13. mindroot/lib/chatcontext.py +100 -4
  14. mindroot/lib/chatlog.py +52 -14
  15. mindroot/lib/chatlog_optimized.py +509 -0
  16. mindroot/lib/plugins/default_plugin_manifest.json +1 -1
  17. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/METADATA +1 -1
  18. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/RECORD +22 -26
  19. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/WHEEL +1 -1
  20. mindroot/coreplugins/google_auth/README.md +0 -76
  21. mindroot/coreplugins/google_auth/__init__.py +0 -1
  22. mindroot/coreplugins/google_auth/inject/login.jinja2 +0 -69
  23. mindroot/coreplugins/google_auth/mod.py +0 -1
  24. mindroot/coreplugins/google_auth/router.py +0 -170
  25. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/entry_points.txt +0 -0
  26. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/licenses/LICENSE +0 -0
  27. {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/top_level.txt +0 -0
@@ -199,6 +199,19 @@ async def scan_directory(request: DirectoryRequest):
199
199
  discovered_plugins = discover_plugins(directory)
200
200
  manifest = load_plugin_manifest()
201
201
  print("discoverd_plugins", discovered_plugins)
202
+
203
+ # Analyze plugins for index compatibility
204
+ addable_count = 0
205
+ for plugin_name, plugin_info in discovered_plugins.items():
206
+ # Check if plugin has GitHub info
207
+ has_github = (
208
+ plugin_info.get('github_url') or
209
+ plugin_info.get('remote_source') or
210
+ (plugin_info.get('metadata', {}).get('github_url'))
211
+ )
212
+ if has_github:
213
+ addable_count += 1
214
+
202
215
  # Update installed plugins from discovered ones
203
216
  for plugin_name, plugin_info in discovered_plugins.items():
204
217
  plugin_info['source'] = 'local'
@@ -218,9 +231,14 @@ async def scan_directory(request: DirectoryRequest):
218
231
  } for name, info in discovered_plugins.items()]
219
232
 
220
233
  save_plugin_manifest(manifest)
221
- return {"success": True,
222
- "message": f"Scanned {len(discovered_plugins)} plugins in {directory}",
223
- "plugins": plugins_list}
234
+
235
+ response = {"success": True,
236
+ "message": f"Scanned {len(discovered_plugins)} plugins in {directory}",
237
+ "plugins": plugins_list,
238
+ "addable_to_index": addable_count}
239
+ if addable_count < len(discovered_plugins):
240
+ response["warning"] = f"{len(discovered_plugins) - addable_count} plugins missing GitHub info and cannot be added to indices"
241
+ return response
224
242
  except Exception as e:
225
243
  trace = traceback.format_exc()
226
244
  return {"success": False, "message": f"Error during scan: {str(e)}\n\n{trace}"}
@@ -67,6 +67,10 @@ class AgentForm extends BaseEl {
67
67
  background: rgba(255, 255, 255, 0.02);
68
68
  }
69
69
 
70
+ .form-hidden-when-no-agent {
71
+ display: none !important;
72
+ }
73
+
70
74
  .form-group {
71
75
  margin-bottom: 15px;
72
76
  }
@@ -1030,13 +1034,26 @@ class AgentForm extends BaseEl {
1030
1034
  }
1031
1035
 
1032
1036
  _render() {
1037
+ // Default structure for rendering when this.agent is null
1038
+ // This ensures the DOM structure is present but hidden.
1039
+ const agentForRender = this.agent || {
1040
+ name: '',
1041
+ persona: '',
1042
+ instructions: '',
1043
+ technicalInstructions: '',
1044
+ uncensored: false,
1045
+ thinking_level: 'off',
1046
+ // commands, preferred_providers, etc., are handled by helper functions
1047
+ // which use optional chaining (this.agent?.property) and are safe.
1048
+ };
1049
+
1033
1050
  return html`
1034
1051
  <div class="agent-selector">
1035
1052
  <select @change=${this.handleAgentChange}
1036
1053
  .value=${this.selectedAgentName || ''}>
1037
1054
  <option value="">Select an agent</option>
1038
1055
  ${this.agents.map(agent => html`
1039
- <option value=${agent.name} ?selected=${agent.name === this.selectedAgentName}>${agent.name}</option>
1056
+ <option .value=${agent.name} ?selected=${agent.name === this.selectedAgentName}>${agent.name}</option>
1040
1057
  `)}
1041
1058
  </select>
1042
1059
  <button class="btn btn-secondary" @click=${this.handleNewAgent}>
@@ -1044,23 +1061,22 @@ class AgentForm extends BaseEl {
1044
1061
  </button>
1045
1062
  </div>
1046
1063
 
1047
- ${this.agent ? html`
1048
- <form class="agent-form" @submit=${this.handleSubmit}>
1064
+ <form class="agent-form ${!this.agent ? 'form-hidden-when-no-agent' : ''}" @submit=${this.handleSubmit}>
1049
1065
  <div class="form-group">
1050
1066
  <label class="required">Name:</label>
1051
1067
  <input type="text" name="name"
1052
- .value=${this.agent.name || ''}
1068
+ .value=${agentForRender.name || ''}
1053
1069
  @input=${this.handleInputChange}>
1054
1070
  </div>
1055
1071
 
1056
1072
  <div class="form-group">
1057
1073
  <label class="required">Persona:</label>
1058
1074
  <select name="persona"
1059
- value=${this.agent.persona || ''}
1075
+ .value=${agentForRender.persona || ''}
1060
1076
  @change=${this.handleInputChange}>
1061
1077
  <option value="">Select a persona</option>
1062
1078
  ${this.personas.map(persona => html`
1063
- <option value="${persona.name}" ?selected=${persona.name === this.agent.persona}>${persona.name}</option>
1079
+ <option value="${persona.name}" ?selected=${persona.name === agentForRender.persona}>${persona.name}</option>
1064
1080
  `)}
1065
1081
  </select>
1066
1082
  </div>
@@ -1084,11 +1100,11 @@ class AgentForm extends BaseEl {
1084
1100
  </div>
1085
1101
  ${this.showInstructionsEditor ? html`
1086
1102
  <textarea name="instructions"
1087
- .value=${this.agent.instructions || ''}
1103
+ .value=${agentForRender.instructions || ''}
1088
1104
  @input=${this.handleInputChange}></textarea>
1089
1105
  ` : html`
1090
1106
  <div class="markdown-preview">
1091
- ${unsafeHTML(this.renderMarkdown(this.agent.instructions || ''))}
1107
+ ${unsafeHTML(this.renderMarkdown(agentForRender.instructions || ''))}
1092
1108
  </div>
1093
1109
  `}
1094
1110
  </div>
@@ -1112,11 +1128,11 @@ class AgentForm extends BaseEl {
1112
1128
  </div>
1113
1129
  ${this.showTechnicalInstructionsEditor ? html`
1114
1130
  <textarea name="technicalInstructions"
1115
- .value=${this.agent.technicalInstructions || ''}
1131
+ .value=${agentForRender.technicalInstructions || ''}
1116
1132
  @input=${this.handleInputChange}></textarea>
1117
1133
  ` : html`
1118
1134
  <div class="markdown-preview">
1119
- ${unsafeHTML(this.renderMarkdown(this.agent.technicalInstructions || ''))}
1135
+ ${unsafeHTML(this.renderMarkdown(agentForRender.technicalInstructions || ''))}
1120
1136
  </div>
1121
1137
  `}
1122
1138
  </div>
@@ -1125,7 +1141,7 @@ class AgentForm extends BaseEl {
1125
1141
  <label>
1126
1142
  Uncensored:
1127
1143
  <toggle-switch
1128
- .checked=${this.agent.uncensored || false}
1144
+ .checked=${agentForRender.uncensored || false}
1129
1145
  @toggle-change=${(e) => this.handleInputChange({
1130
1146
  target: {
1131
1147
  name: 'uncensored',
@@ -1140,22 +1156,22 @@ class AgentForm extends BaseEl {
1140
1156
  <div class="form-group reasoning-level-group">
1141
1157
  <label>Reasoning Effort:</label>
1142
1158
  <select name="thinking_level"
1143
- value=${this.agent.thinking_level || 'off'}
1159
+ .value=${agentForRender.thinking_level || 'off'}
1144
1160
  @change=${this.handleInputChange}>
1145
1161
  <option value="off"
1146
- ?selected=${(this.agent.thinking_level || 'off') === 'off'}>
1162
+ ?selected=${(agentForRender.thinking_level || 'off') === 'off'}>
1147
1163
  Off
1148
1164
  </option>
1149
1165
  <option value="low"
1150
- ?selected=${(this.agent.thinking_level || 'off') === 'low'}>
1166
+ ?selected=${(agentForRender.thinking_level || 'off') === 'low'}>
1151
1167
  Low
1152
1168
  </option>
1153
1169
  <option value="medium"
1154
- ?selected=${(this.agent.thinking_level || 'off') === 'medium'}>
1170
+ ?selected=${(agentForRender.thinking_level || 'off') === 'medium'}>
1155
1171
  Medium
1156
1172
  </option>
1157
1173
  <option value="high"
1158
- ?selected=${(this.agent.thinking_level || 'off') === 'high'}>
1174
+ ?selected=${(agentForRender.thinking_level || 'off') === 'high'}>
1159
1175
  High
1160
1176
  </option>
1161
1177
  </select>
@@ -1184,11 +1200,11 @@ class AgentForm extends BaseEl {
1184
1200
  </details>
1185
1201
  </div>
1186
1202
 
1187
- ${this.agent.name && this.missingCommands && Object.keys(this.missingCommands).length > 0 ? html`
1203
+ ${this.agent?.name && this.missingCommands && Object.keys(this.missingCommands).length > 0 ? html`
1188
1204
  <div class="form-group commands-section">
1189
1205
  <details>
1190
1206
  <summary>Missing Commands (${Object.keys(this.missingCommands).length})</summary>
1191
- <missing-commands .agentName=${this.agent.name}></missing-commands>
1207
+ <missing-commands .agentName=${this.agent.name}></missing-commands> <!-- this.agent.name is safe due to condition -->
1192
1208
  </details>
1193
1209
  </div>
1194
1210
  ` : ''}
@@ -1203,13 +1219,13 @@ class AgentForm extends BaseEl {
1203
1219
  <button class="btn" type="submit" ?disabled=${this.loading}>
1204
1220
  ${this.loading ? 'Saving...' : 'Save'}
1205
1221
  </button>
1206
-
1207
- </form>
1208
- ` : html`
1222
+ </form>
1223
+
1224
+ ${!this.agent ? html`
1209
1225
  <div class="no-agent-message">
1210
1226
  Select an agent from the dropdown above or click "New Agent" to create one.
1211
1227
  </div>
1212
- `}
1228
+ ` : ''}
1213
1229
  `;
1214
1230
  }
1215
1231
  }
@@ -187,6 +187,14 @@ export class PluginAdvancedInstall extends PluginBase {
187
187
  if (response.success) {
188
188
  this.installDialog.addOutput(response.message, 'success');
189
189
 
190
+ // Show index compatibility info
191
+ if (response.addable_to_index !== undefined) {
192
+ this.installDialog.addOutput(`Index-compatible plugins: ${response.addable_to_index}/${response.plugins.length}`, 'info');
193
+ }
194
+ if (response.warning) {
195
+ this.installDialog.addOutput(response.warning, 'warning');
196
+ }
197
+
190
198
  // If plugins were found, list them
191
199
  if (response.plugins && response.plugins.length > 0) {
192
200
  this.installDialog.addOutput('Found plugins:', 'info');
@@ -357,3 +357,21 @@ If you do not do this, then your reasoning will not make it into the chat histor
357
357
  and you will end up repeating the same thought process after every command!
358
358
 
359
359
  {% endblock %}
360
+
361
+ {% block reasoning_reminder_3 %}
362
+
363
+ # Reasonable Reasoning for Commands
364
+
365
+ IMPORTANT:
366
+
367
+ If you have a built-in thinking/reasoning stage and are handling a multiple step
368
+ or iterative process, **DO NOT TRY TO PLAN THE DETAILS OF ALL STEPS IN ADVANCE**.
369
+ Your built-in reasoning efforts are discarded after each batch of commands you output.
370
+ So planning all of the remaining steps in advance each time is very wasteful.
371
+ Instead, you should **only plan for the next few commands that you need to execute**.
372
+ Then you can adjust based on the output of your commands which will be returned
373
+ by the system.
374
+
375
+ {% endblock %}
376
+
377
+
@@ -127,7 +127,15 @@ async def delegate_task(instructions: str, agent_name, log_id=None, retries=3, c
127
127
  Note: do not specify any other arguments than those in the example.
128
128
  In particular, 'context' is not a valid argument!
129
129
 
130
- Use something unique for the log_id.
130
+ log_id is optional, if you specify it you must use something unique.
131
+
132
+ You can also let the system assign log_id automatically:
133
+
134
+ Example:
135
+
136
+ { "delegate_task": { "instructions": "Write a poem about the moon", "agent_name": "poet" } }
137
+
138
+
131
139
  """
132
140
  print("in delegate task, context is:")
133
141
  print(context)
@@ -140,8 +148,9 @@ async def delegate_task(instructions: str, agent_name, log_id=None, retries=3, c
140
148
  elif 'llm' in context.data:
141
149
  llm = context.data['llm']
142
150
  (text, full_results, xx) = await service_manager.run_task(instructions, user=context.username, log_id=log_id,
151
+ parent_log_id = context.log_id,
143
152
  llm=llm, agent_name=agent_name, retries=retries, context=None)
144
- return f"""<a href="/session/{agent_name}/{log_id}" target="_blank">Task completed in log ID: {log_id}</a>\nResults:\n\n{text}"""
153
+ return f"""<a href="/session/{agent_name}/{log_id}" target="_blank">Task completed with log ID: {log_id}</a>\nResults:\n\n{text}"""
145
154
 
146
155
 
147
156
  @command()
@@ -1,4 +1,4 @@
1
- from fastapi import APIRouter, HTTPException, Request, Response
1
+ from fastapi import APIRouter, HTTPException, Request, Response, Depends
2
2
  from fastapi.responses import HTMLResponse, RedirectResponse
3
3
  from fastapi import File, UploadFile, Form
4
4
  from sse_starlette.sse import EventSourceResponse
@@ -6,6 +6,7 @@ from .models import MessageParts
6
6
  from lib.providers.services import service, service_manager
7
7
  from .services import init_chat_session, send_message_to_agent, subscribe_to_agent_messages, get_chat_history, run_task
8
8
  from lib.templates import render
9
+ from lib.auth.auth import require_user
9
10
  from lib.plugins import list_enabled
10
11
  import nanoid
11
12
  from lib.providers.commands import *
@@ -17,6 +18,8 @@ from lib.providers.commands import command_manager
17
18
  from lib.utils.debug import debug_box
18
19
  from lib.session_files import load_session_data, save_session_data
19
20
  import os
21
+ import json
22
+ from lib.chatcontext import ChatContext
20
23
  import shutil
21
24
  from pydantic import BaseModel
22
25
 
@@ -241,6 +244,50 @@ async def get_token_count(request: Request, log_id: str):
241
244
 
242
245
  return {"status": "ok", "token_counts": token_counts}
243
246
 
247
+ @router.get("/chat/del_session/{log_id}")
248
+ async def delete_chat_session(request: Request, log_id: str, user=Depends(require_user)):
249
+ """
250
+ Delete a chat session by log_id, including chat logs, context files, and all child sessions.
251
+
252
+ Parameters:
253
+ - log_id: The log ID of the session to delete
254
+
255
+ Returns:
256
+ - JSON with success status and message
257
+ """
258
+ try:
259
+ # Try to determine the agent name from the context file first
260
+ agent_name = "unknown"
261
+ context_file_path = f"data/context/{user.username}/context_{log_id}.json"
262
+
263
+ if os.path.exists(context_file_path):
264
+ try:
265
+ with open(context_file_path, 'r') as f:
266
+ context_data = json.load(f)
267
+ agent_name = context_data.get('agent_name', 'unknown')
268
+ print(f"Found agent name '{agent_name}' from context file for log_id {log_id}")
269
+ except Exception as e:
270
+ print(f"Error reading context file {context_file_path}: {e}")
271
+
272
+ # If we still don't have the agent name, try to find the chatlog file
273
+ if agent_name == "unknown":
274
+ from lib.chatlog import find_chatlog_file
275
+ chatlog_path = find_chatlog_file(log_id)
276
+ if chatlog_path:
277
+ # Extract agent from path: data/chat/{user}/{agent}/chatlog_{log_id}.json
278
+ path_parts = chatlog_path.split(os.sep)
279
+ if len(path_parts) >= 3:
280
+ agent_name = path_parts[-2] # Agent is the second-to-last part
281
+ print(f"Found agent name '{agent_name}' from chatlog file path for log_id {log_id}")
282
+
283
+ await ChatContext.delete_session_by_id(log_id=log_id, user=user.username, agent=agent_name, cascade=True)
284
+
285
+ return {"status": "ok", "message": f"Chat session {log_id} deleted successfully"}
286
+ except Exception as e:
287
+ print(f"Error deleting chat session {log_id}: {e}")
288
+ raise HTTPException(status_code=500, detail=f"Error deleting chat session: {str(e)}")
289
+
290
+
244
291
  @router.get("/chat/{log_id}/tokens")
245
292
  async def get_token_count(request: Request, log_id: str):
246
293
  """
@@ -50,7 +50,8 @@ def results_text_output(results):
50
50
 
51
51
 
52
52
  @service()
53
- async def run_task(instructions: str, agent_name:str = None, user:str = None, log_id=None, llm=None, retries=3, context=None):
53
+ async def run_task(instructions: str, agent_name:str = None, user:str = None, log_id=None,
54
+ parent_log_id=None, llm=None, retries=3, context=None):
54
55
  """
55
56
  Run a task with the given instructions
56
57
  IMPORTANT NOTE: agent must have the task_result() command enabled.
@@ -70,10 +71,11 @@ async def run_task(instructions: str, agent_name:str = None, user:str = None, lo
70
71
  context.username = user
71
72
  context.name = agent_name
72
73
  context.log_id = log_id
74
+ context.parent_log_id = parent_log_id
73
75
  context.agent = await service_manager.get_agent_data(agent_name)
74
76
  context.data['llm'] = llm
75
77
  context.current_model = llm
76
- context.chat_log = ChatLog(log_id=log_id, agent=agent_name, user=user)
78
+ context.chat_log = ChatLog(log_id=log_id, agent=agent_name, user=user, parent_log_id=parent_log_id)
77
79
  context.save_context()
78
80
  else:
79
81
  debug_box("Context is not none")
@@ -11,44 +11,50 @@
11
11
  "version": "1.0.0",
12
12
  "description": "Simple Google search functionality",
13
13
  "source": "github",
14
- "github_url": "runvnc/ah_google",
14
+ "github_url": "https://github.com/runvnc/ah_google",
15
15
  "commands": ["google", "fetch_webpage"],
16
16
  "services": [],
17
17
  "dependencies": []
18
18
  },
19
19
  {
20
- "name": "Think (Chain-of-Thought)",
20
+ "name": "ah_think",
21
21
  "version": "0.0.1",
22
22
  "description": "Chain of thought reasoning capability",
23
- "source": "local",
24
- "source_path": "/xfiles/plugins_ah/ah_think",
23
+ "source": "github",
24
+ "github_url": "https://github.com/runvnc/ah_think",
25
25
  "commands": ["think"],
26
26
  "services": [],
27
27
  "dependencies": []
28
28
  },
29
29
  {
30
- "name": "Look at PDF/Image",
30
+ "name": "ah_look_at",
31
31
  "version": "0.0.1",
32
32
  "description": "PDF and image examination tools",
33
- "source": "local",
34
- "source_path": "/xfiles/plugins_ah/ah_look_at",
33
+ "source": "github",
34
+ "github_url": "https://github.com/runvnc/ah_look_at",
35
35
  "commands": ["examine_pdf", "examine_image"],
36
36
  "services": [],
37
37
  "dependencies": []
38
38
  },
39
39
  {
40
- "enabled": true,
41
- "source": "github",
42
- "source_path": "runvnc/ah_anthropic",
40
+ "name": "ah_anthropic",
43
41
  "version": "0.0.1",
44
- "name": "Anthropic (Claude)"
42
+ "description": "Anthropic Claude AI integration",
43
+ "source": "github",
44
+ "github_url": "https://github.com/runvnc/ah_anthropic",
45
+ "commands": [],
46
+ "services": [],
47
+ "dependencies": []
45
48
  },
46
49
  {
47
- "enabled": true,
48
- "source": "github",
49
- "source_path": "runvnc/ah_shell",
50
+ "name": "ah_shell",
50
51
  "version": "0.0.1",
51
- "name": "Shell"
52
+ "description": "Shell command execution",
53
+ "source": "github",
54
+ "github_url": "https://github.com/runvnc/ah_shell",
55
+ "commands": ["execute_command"],
56
+ "services": [],
57
+ "dependencies": []
52
58
  }
53
59
  ],
54
60
  "agents": [
@@ -82,6 +82,19 @@ async def add_plugin(INDEX_DIR: Path, index_name: str, plugin: PluginEntry):
82
82
  if not index_file.exists():
83
83
  return JSONResponse({'success': False, 'message': 'Index not found'})
84
84
 
85
+ # Early validation - check for required GitHub info
86
+ has_github_info = (
87
+ plugin.remote_source or
88
+ plugin.github_url or
89
+ getattr(plugin, 'metadata', {}).get('github_url')
90
+ )
91
+
92
+ if not has_github_info:
93
+ return JSONResponse({
94
+ 'success': False,
95
+ 'message': 'Plugin missing GitHub repository information. Cannot add to index.'
96
+ })
97
+
85
98
  # Check if plugin is local
86
99
  if plugin.source == 'local':
87
100
  return JSONResponse({
@@ -346,8 +346,9 @@
346
346
  "flags": [],
347
347
  "uncensored": false,
348
348
  "commands": [
349
- "say",
350
- "json_encoded_md",
349
+ "wait_for_user_reply",
350
+ "tell_and_continue",
351
+ "markdown_await_user",
351
352
  "read",
352
353
  "write",
353
354
  "dir",
@@ -369,8 +370,9 @@
369
370
  "persona": "Dr_Alex_Morgan",
370
371
  "instructions": "### Clinical Approach\\n\\nDr. Alex Morgan uses a client-centered approach, focusing on creating a safe and non-judgmental space. The primary techniques include cognitive restructuring, behavioral activation, exposure therapy, mindfulness, and goal setting.\\n\\n### Key CBT Skills and Techniques\\n\\n#### Cognitive Restructuring\\n- **Identify Negative Thoughts:** Use thought diaries to track negative thoughts.\\n- **Examine Evidence:** Evaluate evidence for and against negative thoughts.\\n- **Challenge Thoughts:** Use Socratic questioning (e.g., \\\"What is the evidence for this thought?\\\").\\n- **Replace Thoughts:** Develop balanced and realistic thoughts.\\n- **Practice:** Encourage regular practice of cognitive restructuring.\\n\\n#### Behavioral Activation\\n- **Activity Monitoring:** Track daily activities and mood.\\n- **Activity Scheduling:** Schedule enjoyable and meaningful activities.\\n- **Gradual Task Assignment:** Start with small tasks and gradually increase difficulty.\\n- **Review and Adjust:** Regularly review progress and adjust the plan.\\n- **Reinforce Positive Behavior:** Celebrate achievements to reinforce positive behavior.\\n\\n#### Goal Setting\\n- **SMART Goals:** Ensure goals are Specific, Measurable, Achievable, Relevant, and Time-bound.\\n- **Break Down Goals:** Divide larger goals into smaller steps.\\n- **Action Plan:** Create a detailed action plan with tasks and deadlines.\\n- **Monitor Progress:** Regularly review progress and provide feedback.\\n- **Celebrate Successes:** Acknowledge and celebrate achievements.\\n\\n### Overall Process\\n\\n1. **Initial Consultation:** Assess client's history, issues, and goals.\\n2. **Treatment Planning:** Develop a personalized treatment plan.\\n3. **Therapy Sessions:** Conduct regular sessions using CBT techniques.\\n4. **Progress Monitoring:** Review progress and adjust the plan.\\n5. **Termination and Follow-Up:** Gradually reduce sessions and develop a relapse prevention plan.\\n\\n### Per-Session Process\\n\\n1. **Check-In:** Discuss client's current mood and experiences.\\n2. **Review Homework:** Discuss homework assignments.\\n3. **Agenda Setting:** Set the session's agenda.\\n4. **CBT Interventions:** Implement CBT techniques.\\n5. **Skill Building:** Teach and practice new CBT skills.\\n6. **Homework Assignment:** Assign tasks for practice.\\n7. **Session Summary:** Summarize key points and provide feedback.\\n8. **Planning for Next Session:** Discuss focus and goals for the next session.",
371
372
  "commands": [
372
- "say",
373
- "json_encoded_md"
373
+ "wait_for_user_reply",
374
+ "tell_and_continue",
375
+ "markdown_await_user"
374
376
  ],
375
377
  "flags": [],
376
378
  "added_at": "2024-12-08T17:08:22.219537",
@@ -381,8 +383,9 @@
381
383
  "name": "Mindroot Engineering Expert",
382
384
  "persona": "Assistant",
383
385
  "commands": [
384
- "say",
385
- "json_encoded_md",
386
+ "wait_for_user_reply",
387
+ "tell_and_continue",
388
+ "markdown_await_user",
386
389
  "think",
387
390
  "memory_add",
388
391
  "memory_update",
@@ -96,6 +96,18 @@ class PluginSection extends BaseEl {
96
96
  opacity: 0.5;
97
97
  cursor: not-allowed;
98
98
  }
99
+
100
+ .plugin-warning {
101
+ font-size: 0.8rem;
102
+ color: #f39c12;
103
+ margin-top: 4px;
104
+ }
105
+
106
+ .disabled {
107
+ background: #555 !important;
108
+ color: #999 !important;
109
+ cursor: not-allowed !important;
110
+ }
99
111
  `;
100
112
 
101
113
  constructor() {
@@ -103,6 +115,22 @@ class PluginSection extends BaseEl {
103
115
  this.searchTerm = '';
104
116
  }
105
117
 
118
+ isPluginAddable(plugin) {
119
+ // Must have GitHub source info
120
+ const hasGitHubInfo = plugin.remote_source ||
121
+ plugin.github_url ||
122
+ (plugin.metadata && plugin.metadata.github_url);
123
+
124
+ // Must not be local source
125
+ const isNotLocal = plugin.source !== 'local';
126
+
127
+ // Must have basic metadata
128
+ const hasMetadata = plugin.metadata &&
129
+ (plugin.metadata.commands || plugin.metadata.services);
130
+
131
+ return hasGitHubInfo && isNotLocal && hasMetadata;
132
+ }
133
+
106
134
  filterPlugins(plugins) {
107
135
  if (!plugins) return [];
108
136
  const searchLower = this.searchTerm?.toLowerCase() || '';
@@ -165,6 +193,9 @@ class PluginSection extends BaseEl {
165
193
  <div class="plugin-description">${plugin.description}</div>
166
194
  ` : ''}
167
195
  <div class="plugin-source">Source: ${plugin.source}</div>
196
+ ${!this.isPluginAddable(plugin) ? html`
197
+ <div class="plugin-warning">⚠️ Missing GitHub info - cannot add to index</div>
198
+ ` : ''}
168
199
  </div>
169
200
  ${isIndexPlugins ? html`
170
201
  <button class="action-button remove-button"
@@ -172,11 +203,17 @@ class PluginSection extends BaseEl {
172
203
  Remove
173
204
  </button>
174
205
  ` : html`
175
- <button class="action-button add-button"
176
- ?disabled=${this.selectedIndex?.plugins?.some(p => p.name === plugin.name)}
177
- @click=${() => this.handleAddPlugin(plugin)}>
178
- Add
179
- </button>
206
+ ${this.isPluginAddable(plugin) ? html`
207
+ <button class="action-button add-button"
208
+ ?disabled=${this.selectedIndex?.plugins?.some(p => p.name === plugin.name)}
209
+ @click=${() => this.handleAddPlugin(plugin)}>
210
+ Add
211
+ </button>
212
+ ` : html`
213
+ <button class="action-button disabled" disabled title="Missing GitHub repository information">
214
+ Cannot Add
215
+ </button>
216
+ `}
180
217
  `}
181
218
  </div>
182
219
  `)}
@@ -50,6 +50,7 @@
50
50
  background-color: #45a049;
51
51
  }
52
52
  </style>
53
+ {% block head_extra %}{% endblock %}
53
54
  <script>
54
55
  async function handleLogin(event) {
55
56
  event.preventDefault();
@@ -78,8 +79,10 @@
78
79
  <input type="password" name="password" placeholder="Password" required>
79
80
  <button type="submit">Log In</button>
80
81
  </form>
82
+ {% block content %}{% endblock %}
81
83
  <div>
82
84
  <p>Don't have an account? <a href="/signup">Sign Up</a></p>
85
+ </div>
83
86
  </div>
84
87
  </body>
85
- </html>
88
+ </html>