octomind 0.16.0

Session-based AI development assistant with conversational codebase interaction, multimodal vision support, built-in MCP tools, and multi-provider AI integration
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
// Copyright 2025 Muvon Un Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Optimized function definitions module - MCP function specifications with reduced tokens

use super::super::McpFunction;
use serde_json::json;

// Define the list_files function - optimized
pub fn get_list_files_function() -> McpFunction {
	McpFunction {
		name: "list_files".to_string(),
		description: "List files in a directory, with optional pattern matching.

			This tool uses ripgrep for efficient searching that respects .gitignore files.
			You can use it to find files by name pattern or search for files containing specific content.

			PERFORMANCE WARNING: Use filtering to avoid large outputs that consume excessive tokens

			Parameters:
			- `directory`: Target directory to search
			- `pattern`: Optional filename pattern (uses ripgrep syntax)
			- `content`: Optional content search within files
			- `max_depth`: Optional depth limit for directory traversal
			- `include_hidden`: Include hidden files/directories starting with '.' (default: false)
			- `line_numbers`: Show line numbers for content search (default: true)
			- `context`: Number of context lines to show around matches (default: 0)

			Note: Response size is controlled by global mcp_response_tokens_threshold setting.
			Use specific patterns and filters to reduce output size if responses are truncated.

			Best Practices:
			- Always use specific patterns - avoid listing entire large directories
			- Use max_depth to limit scope and reduce token usage
			- Combine with content search when looking for specific functionality
			- Filter by file type using patterns like '*.rs' or '*.toml'
			- Use include_hidden=false (default) to exclude dotfiles for cleaner results

			Examples:
			- Find Rust files: `{\"directory\": \"src\", \"pattern\": \"*.rs\"}`
			- Find config files: `{\"directory\": \".\", \"pattern\": \"*.toml|*.yaml|*.json\"}`
			- Search for function: `{\"directory\": \"src\", \"content\": \"fn main\"}`
			- Limited depth: `{\"directory\": \".\", \"max_depth\": 2, \"pattern\": \"*.rs\"}`
			- Include dotfiles: `{\"directory\": \".\", \"pattern\": \".*rc\", \"include_hidden\": true}`
			- Find hidden configs: `{\"directory\": \".\", \"include_hidden\": true, \"pattern\": \"*.json|*.yaml\"}`

			Token-Efficient Usage:
			- Use patterns to target specific file types
			- Set max_depth to avoid deep directory traversals
			- Combine with content search for targeted results
			- Prefer multiple specific calls over one broad search"
			.to_string(),
		parameters: json!({
			"type": "object",
			"required": ["directory"],
			"properties": {
				"directory": {
					"type": "string",
					"description": "The directory to list files from"
				},
				"pattern": {
					"type": "string",
					"description": "Optional pattern to match filenames (uses ripgrep)"
				},
				"content": {
					"type": "string",
					"description": "Optional content to search for in files (uses ripgrep)"
				},
				"max_depth": {
					"type": "integer",
					"description": "Maximum depth of directories to descend (default: no limit)"
				},
				"include_hidden": {
					"type": "boolean",
					"default": false,
					"description": "Include hidden files and directories starting with '.' (default: false)"
				},
				"line_numbers": {
					"type": "boolean",
					"default": true,
					"description": "Show line numbers for content search (default: true)"
				},
				"context": {
					"type": "integer",
					"default": 0,
					"description": "Number of context lines to show around matches (default: 0)"
				}
			}
		}),
	}
}

// Define the text editor function - DRAMATICALLY OPTIMIZED
pub fn get_text_editor_function() -> McpFunction {
	McpFunction {
		name: "text_editor".to_string(),
		description: "Perform text editing operations on files with comprehensive file manipulation capabilities.

			The `command` parameter specifies the operation to perform.

			CRITICAL: LINE NUMBERS CHANGE AFTER EVERY EDIT OPERATION!
			- After ANY edit (str_replace, insert, line_replace), line numbers become invalid
			- ALWAYS use 'view' command first to get current line numbers before line_replace
			- PREFER line_replace when you know exact lines (fastest), str_replace when you know content
			- new_str contains RAW FILE CONTENT - use actual whitespace characters, not escape sequences (tabs=actual tabs, NOT \\t)!
			- FOR MULTIPLE EDITS: Use batch_edit tool instead if file hasn't been modified yet

			Available commands:

			`view`: Examine file content or list directory contents
			- View entire file: `{\"command\": \"view\", \"path\": \"src/main.rs\"}`
			- View specific lines: `{\"command\": \"view\", \"path\": \"src/main.rs\", \"view_range\": [10, 20]}`
			- List directory: `{\"command\": \"view\", \"path\": \"src/\"}`
			- Returns content as plain text with line numbers (1-indexed) for editing reference
			- Smart elision: when using view_range, shows context with [...X lines more] indicators

			`create`: Create new file with specified content
			- `{\"command\": \"create\", \"path\": \"src/new_module.rs\", \"file_text\": \"pub fn hello() {\\n    println!(\\\"Hello!\\\");\\n}\"}`
			- Creates parent directories if they don't exist
			- Returns error if file already exists to prevent accidental overwrites

			`str_replace`: Replace specific string in file with new content
			- `{\"command\": \"str_replace\", \"path\": \"src/main.rs\", \"old_str\": \"fn old_name()\", \"new_str\": \"fn new_name()\"}`
			- The old_str must match exactly, including whitespace and indentation
			- Returns error if string appears 0 times or more than once for safety
			- Content-based replacement - works regardless of line numbers
			- Use when exact text is known but line numbers uncertain

			`insert`: Insert text at specific location in file
			- `{\"command\": \"insert\", \"path\": \"src/main.rs\", \"insert_line\": 5, \"new_str\": \"    // New comment\\n    let x = 10;\"}`
			- insert_line specifies the line number after which to insert (0 for beginning of file)
			- WARNING: Changes line numbers for all content AFTER insertion point

			`line_replace`: Replace content within specific line range
			- `{\"command\": \"line_replace\", \"path\": \"src/main.rs\", \"view_range\": [5, 8], \"new_str\": \"fn updated_function() {\\n    // New implementation\\n}\"}`
			- Replaces lines from view_range[0] to view_range[1] (inclusive, 1-indexed)
			- FASTEST option - 3x faster than str_replace (no content searching)
			- **REMOVE LINES**: Use empty `new_str` (\"\" or \"\") to remove lines completely
			- **USEFUL FOR REFACTORING**: Extract code with `extract_lines`, then remove original with `line_replace` + empty `new_str`
			- CRITICAL: Line numbers change after ANY edit operation
			- NEVER use line_replace twice without viewing file between operations
			- ALWAYS use 'view' first to get current line numbers before line_replace

			`view_many`: View multiple files simultaneously
			- `{\"command\": \"view_many\", \"paths\": [\"src/main.rs\", \"src/lib.rs\", \"tests/test.rs\"]}`
			- Returns content with line numbers for all files in a single operation
			- Maximum 50 files per request to maintain performance

			`undo_edit`: Revert most recent edit to specified file
			- `{\"command\": \"undo_edit\", \"path\": \"src/main.rs\"}`
			- Available for str_replace, insert, and line_replace operations

			Error Handling:
			- File not found: Returns descriptive error message
			- Multiple matches: Returns error asking for more specific context
			- No matches: Returns error with suggestion to check the text
			- Permission errors: Returns permission denied message
			- Line range errors: Validates line numbers exist in file

			Best Practices:
			- ALWAYS use 'view' first to get current line numbers before any edit
			- Never assume line numbers from previous operations - they change after every edit

			OPTIMAL WORKFLOW:
			- Use `view` to see file structure and get line numbers
			- For single changes: use `line_replace` ONCE per file
			- If more edits needed: `view` again to get fresh line numbers, then `line_replace` again

			CHOOSE line_replace when:
			- You know exact line numbers and need to change one or more lines with new
			- Want 3x faster performance (no content searching needed)
			- ONLY ONE line_replace per file before re-viewing
			- File has already been modified (line numbers changed)

			CHOOSE str_replace when:
			- Modifying existing code/content (not building new)
			- You know exact text content but not line numbers
			- Changing existing function implementations or config values
			- File has been modified and you can't trust line numbers

			CHOOSE batch_edit when:
			- Multiple edits needed on UNMODIFIED file (2+ operations)
			- File hasn't been edited yet in this session
			- Need atomic operations (all succeed or all fail)

			CHOOSE insert when:
			- Building new documents or adding new sections
			- Adding content that doesn't exist yet
			- Creating plans, documentation, or structured content

			CRITICAL LINE NUMBER RULES:
			- Line numbers become INVALID after ANY edit operation
			- NEVER use line_replace twice without viewing file between operations
			- After str_replace, insert, or line_replace: line numbers change
			- Always view file again to get fresh line numbers before next line_replace
			- ONE line_replace per file per editing session - then re-view if more edits needed

			General Guidelines:
			- Use insert for adding new code at specific locations
			- Use create for new files and modules
			- Use undo_edit to revert the last operation if needed"
			.to_string(),
		parameters: json!({
			"type": "object",
			"required": ["command", "path"],
			"properties": {
				"command": {
					"type": "string",
					"enum": ["view", "view_many", "create", "str_replace", "insert", "line_replace", "undo_edit"],
					"description": "The operation to perform: view, view_many, create, str_replace, insert, line_replace, undo_edit"
				},
				"path": {
					"type": "string",
					"description": "Absolute path to the file or directory (not used for view_many command)"
				},
				"paths": {
					"type": "array",
					"items": {"type": "string"},
					"maxItems": 50,
					"description": "Array of absolute file paths for view_many command"
				},
				"view_range": {
					"type": "array",
					"items": {"type": "integer"},
					"minItems": 2,
					"maxItems": 2,
					"description": "Optional array of two integers [start_line, end_line] for viewing specific lines (1-indexed, -1 for end means read to end of file)"
				},
				"file_text": {
					"type": "string",
					"description": "Content to write when creating a new file"
				},
				"old_str": {
					"type": "string",
					"description": "Text to replace (must match exactly including whitespace)"
				},
				"new_str": {
					"type": "string",
					"description": "Raw file content exactly as it should appear in the file. Use actual tabs/spaces, NOT escape sequences like \\t or \\n. Copy exact indentation from original code. No string literal escaping needed - this is direct file content."
				},
				"insert_line": {
					"type": "integer",
					"minimum": 0,
					"description": "Line number after which to insert text (0 for beginning of file, 1-indexed)"
				},
			}
		}),
	}
}

// Define the extract_lines function
pub fn get_extract_lines_function() -> McpFunction {
	McpFunction {
		name: "extract_lines".to_string(),
		description: "Extract lines from a source file and append them to a target file without modifying the source file.

			This tool is perfect for extracting code blocks, functions, or any text sections from one file
			and appending them to another file. The source file remains unchanged.

			**Parameters:**
			- `from_path` (string, required): Path to the source file to extract lines from
			- `from_range` (array, required): Two-element array [start, end] with 1-indexed line numbers (inclusive)
			- `append_path` (string, required): Path to the target file where extracted lines will be appended (auto-created if doesn't exist)
			- `append_line` (integer, required): Position where to append the extracted content:
			  - `0`: Insert at the beginning of the file
			  - `-1`: Append at the very end of the file
			  - `N` (positive): Insert after line N (1-indexed)

			**Examples:**
			- Extract function: `{\"from_path\": \"src/utils.rs\", \"from_range\": [10, 25], \"append_path\": \"src/extracted.rs\", \"append_line\": -1}`
			- Extract to beginning: `{\"from_path\": \"config.toml\", \"from_range\": [1, 5], \"append_path\": \"new_config.toml\", \"append_line\": 0}`
			- Insert after line 3: `{\"from_path\": \"main.rs\", \"from_range\": [50, 60], \"append_path\": \"module.rs\", \"append_line\": 3}`

			**Use Cases:**
			- Extracting functions or code blocks for refactoring
			- Moving configuration sections between files
			- Creating new files with specific content from existing files
			- Building modular code by extracting reusable components

			**Returns:**
			- Success: Information about extracted lines and where they were appended
			- Error: Clear error message if file not found, invalid range, or write permission issues

			**MCP Protocol Compliance:**
			- Proper parameter validation with descriptive error messages
			- Graceful handling of file system errors
			- Returns structured success/error responses".to_string(),
		parameters: json!({
			"type": "object",
			"properties": {
				"from_path": {
					"type": "string",
					"description": "Path to the source file to extract lines from"
				},
				"from_range": {
					"type": "array",
					"items": {"type": "integer"},
					"minItems": 2,
					"maxItems": 2,
					"description": "Two-element array [start, end] with 1-indexed line numbers (inclusive)"
				},
				"append_path": {
					"type": "string",
					"description": "Path to the target file where extracted lines will be appended (auto-created if doesn't exist)"
				},
				"append_line": {
					"type": "integer",
					"description": "Position where to append: 0=beginning, -1=end, N=after line N (1-indexed)"
				}
			},
			"required": ["from_path", "from_range", "append_path", "append_line"]
		}),
	}
}

// Define the batch_edit function - extracted from text_editor for simplicity
pub fn get_batch_edit_function() -> McpFunction {
	McpFunction {
		name: "batch_edit".to_string(),
		description: "Perform multiple line-based operations on a SINGLE file using original line numbers.

			This tool performs multiple insert and replace operations on a single file in one atomic operation.
			All operations use the ORIGINAL file line numbers before any modifications, ensuring line stability.

			**WHEN TO USE:**
			- Multiple edits in single file (2+ changes)
			- When you need to edit a file that hasn't been modified yet in this session
			- For atomic operations that must all succeed or all fail

			**WHEN NOT TO USE:**
			- After ANY other file edit (text_editor, str_replace, etc.) - line numbers will be wrong
			- For single operations - use text_editor instead
			- On files that have been modified - get fresh line numbers first

			**CRITICAL RULES:**
			- ALL line numbers must reference the ORIGINAL file content (before ANY modifications)
			- After ANY edit operation, line numbers change - don't use batch_edit on modified files
			- Operations applied atomically in reverse order to maintain line stability
			- Conflicts between operations are detected and rejected

			**Parameters:**
			- `path` (string): Path to the file to edit
			- `operations` (array): Array of operations to perform

			**Operation Structure:**
			- `operation`: 'insert' (after line) or 'replace' (line range)
			- `line_range`: Single number for insert, [start, end] array for replace (1-indexed)
			- `content`: Raw text content (no escaping needed)

			**Examples:**
			- Multiple ops: `{\"path\": \"file.rs\", \"operations\": [{\"operation\": \"insert\", \"line_range\": 1, \"content\": \"header\"}, {\"operation\": \"replace\", \"line_range\": [3, 3], \"content\": \"replaced\"}]}`

			**Maximum 50 operations per call for performance**".to_string(),
		parameters: json!({
			"type": "object",
			"properties": {
				"path": {
					"type": "string",
					"description": "Path to the file to edit"
				},
				"operations": {
					"type": "array",
					"items": {
						"type": "object",
						"properties": {
							"operation": {
								"type": "string",
								"enum": ["insert", "replace"],
								"description": "Type of operation: 'insert' (after line) or 'replace' (line range)"
							},
							"line_range": {
								"oneOf": [
									{
										"type": "integer",
										"minimum": 0,
										"description": "Single line number for insert (0=beginning, N=after line N)"
									},
									{
										"type": "array",
										"items": {"type": "integer", "minimum": 1},
										"minItems": 1,
										"maxItems": 2,
										"description": "Line range [start] or [start, end] (1-indexed, inclusive)"
									}
								],
								"description": "CRITICAL: Line numbers from ORIGINAL file content (before any modifications). Insert: single number (after which line). Replace: [start, end] range (inclusive, 1-indexed). DO NOT USE if file was modified - line numbers will be wrong!"
							},
							"content": {
								"type": "string",
								"description": "Raw content to insert or replace with (no escaping needed - use actual tabs/spaces)"
							}
						},
						"required": ["operation", "line_range", "content"]
					},
					"maxItems": 50,
					"description": "Array of operations for batch_edit on SINGLE file. All line_range values reference ORIGINAL file content. DO NOT USE after any file modifications!"
				}
			},
			"required": ["path", "operations"]
		}),
	}
}

// Get all available filesystem functions
pub fn get_all_functions() -> Vec<McpFunction> {
	vec![
		get_text_editor_function(),
		get_batch_edit_function(),
		get_list_files_function(),
		get_extract_lines_function(),
	]
}