minovative-mind-cli 1.5.1 → 2.1.0
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.
- package/README.md +59 -45
- package/dist/commands/chat.js +10 -2
- package/dist/services/agent/slashCommands.js +369 -42
- package/dist/services/agent/toolLoop.d.ts +1 -1
- package/dist/services/agent/toolLoop.js +7 -2
- package/dist/services/agent/types.d.ts +2 -0
- package/dist/services/agent-tools.d.ts +9 -4
- package/dist/services/agent-tools.js +272 -34
- package/dist/services/agent.d.ts +8 -0
- package/dist/services/agent.js +288 -40
- package/dist/services/ai.d.ts +19 -5
- package/dist/services/ai.js +182 -36
- package/dist/services/changeLogger.d.ts +142 -0
- package/dist/services/changeLogger.js +132 -3
- package/dist/services/contextAgent.d.ts +6 -1
- package/dist/services/contextAgent.js +112 -19
- package/dist/services/embeddingIndex.d.ts +82 -0
- package/dist/services/embeddingIndex.js +613 -0
- package/dist/services/investigationComplexity.d.ts +45 -0
- package/dist/services/investigationComplexity.js +91 -0
- package/dist/services/metrics.d.ts +18 -0
- package/dist/services/metrics.js +7 -0
- package/dist/services/orchestration/fileLockRegistry.d.ts +125 -0
- package/dist/services/orchestration/fileLockRegistry.js +276 -0
- package/dist/services/orchestration/investigationAgent.d.ts +85 -0
- package/dist/services/orchestration/investigationAgent.js +362 -0
- package/dist/services/orchestration/investigationOrchestrator.d.ts +53 -0
- package/dist/services/orchestration/investigationOrchestrator.js +180 -0
- package/dist/services/orchestration/messageBus.d.ts +162 -0
- package/dist/services/orchestration/messageBus.js +225 -0
- package/dist/services/orchestration/orchestrator.d.ts +45 -0
- package/dist/services/orchestration/orchestrator.js +217 -0
- package/dist/services/orchestration/readCache.d.ts +79 -0
- package/dist/services/orchestration/readCache.js +108 -0
- package/dist/services/orchestration/scopedTools.d.ts +57 -0
- package/dist/services/orchestration/scopedTools.js +172 -0
- package/dist/services/orchestration/subAgent.d.ts +58 -0
- package/dist/services/orchestration/subAgent.js +190 -0
- package/dist/services/orchestration/taskGraph.d.ts +129 -0
- package/dist/services/orchestration/taskGraph.js +254 -0
- package/dist/services/proxyClient.d.ts +25 -0
- package/dist/services/proxyClient.js +60 -0
- package/dist/services/workspaceRegistry.d.ts +137 -0
- package/dist/services/workspaceRegistry.js +270 -0
- package/dist/utils/asyncContext.d.ts +16 -0
- package/dist/utils/asyncContext.js +25 -0
- package/dist/utils/config.d.ts +3 -1
- package/dist/utils/config.js +3 -1
- package/dist/utils/contextPrompts.js +10 -3
- package/dist/utils/dependencyTracer/modules/api.d.ts +9 -0
- package/dist/utils/dependencyTracer/modules/api.js +62 -0
- package/dist/utils/dependencyTracer/modules/graph.d.ts +9 -0
- package/dist/utils/dependencyTracer/modules/graph.js +23 -0
- package/dist/utils/dependencyTracer/modules/profiles.d.ts +7 -0
- package/dist/utils/dependencyTracer/modules/profiles.js +120 -0
- package/dist/utils/dependencyTracer/modules/resolver.d.ts +7 -0
- package/dist/utils/dependencyTracer/modules/resolver.js +51 -0
- package/dist/utils/dependencyTracer/modules/types.d.ts +4 -0
- package/dist/utils/dependencyTracer/modules/types.js +1 -0
- package/dist/utils/dependencyTracer/modules/walker.d.ts +1 -0
- package/dist/utils/dependencyTracer/modules/walker.js +48 -0
- package/dist/utils/dependencyTracer.js +31 -17
- package/dist/utils/excludedExtensions.js +0 -1
- package/dist/utils/historyPrompt.d.ts +9 -0
- package/dist/utils/historyPrompt.js +87 -0
- package/dist/utils/logo.js +7 -7
- package/dist/utils/paste.d.ts +21 -0
- package/dist/utils/paste.js +22 -1
- package/dist/utils/pathSecurity.d.ts +31 -0
- package/dist/utils/pathSecurity.js +48 -0
- package/dist/utils/profiles.d.ts +2 -0
- package/dist/utils/profiles.js +44 -0
- package/dist/utils/projectStorage.js +10 -7
- package/dist/utils/systemPrompts.d.ts +6 -3
- package/dist/utils/systemPrompts.js +111 -6
- package/dist/utils/types.d.ts +33 -0
- package/dist/utils/types.js +1 -0
- package/oclif.manifest.json +2 -2
- package/package.json +4 -3
package/dist/services/ai.js
CHANGED
|
@@ -1,10 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { GEMINI_MODELS, DEFAULT_MODEL, MAX_OUTPUT_TOKENS } from '../utils/config.js';
|
|
2
|
+
import { getToolDeclarations } from './agent-tools.js';
|
|
3
3
|
import { ProxyClient } from './proxyClient.js';
|
|
4
4
|
import { getAuthorizedIdToken } from './auth.js';
|
|
5
5
|
import { debugLog } from '../utils/logger.js';
|
|
6
|
-
import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
|
|
6
|
+
import { GENERAL_CHAT_INSTRUCTION, PLAN_EXECUTION_INSTRUCTION, PLAN_MODE_INSTRUCTION, CONTEXT_SYSTEM_INSTRUCTION, INTENT_ROUTER_SYSTEM_INSTRUCTION, WEB_SEARCH_SYSTEM_INSTRUCTION, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
|
|
7
|
+
import { getMetricCollector } from './metrics.js';
|
|
8
|
+
import { workspaceRegistry } from './workspaceRegistry.js';
|
|
9
|
+
function getMultiWorkspaceBlock() {
|
|
10
|
+
const summary = workspaceRegistry.buildPromptSummary();
|
|
11
|
+
if (!summary)
|
|
12
|
+
return '';
|
|
13
|
+
return `<multi_workspace>
|
|
14
|
+
The user has registered external workspaces that you can access using the @alias/ prefix:
|
|
15
|
+
${summary}
|
|
16
|
+
|
|
17
|
+
To read, modify, or search files in an external workspace, prefix the file path with the alias (e.g., "@backend/src/routes.ts"). To search across ALL workspaces, use grep_search with workspace="all".
|
|
18
|
+
|
|
19
|
+
When the user asks to "transfer", "sync", or "port" features between projects, read the source files from one workspace and apply the changes to the target.
|
|
20
|
+
</multi_workspace>`;
|
|
21
|
+
}
|
|
22
|
+
// ─── Model Overrides (for Regression Testing) ────────────────────────
|
|
23
|
+
let contextModelOverride = null;
|
|
24
|
+
let contextTempOverride = null;
|
|
25
|
+
let executionModelOverride = null;
|
|
26
|
+
let executionTempOverride = null;
|
|
27
|
+
export function setModelOverride(agent, overrideStr) {
|
|
28
|
+
const [model, temp] = overrideStr.split(':');
|
|
29
|
+
if (agent === 'context') {
|
|
30
|
+
contextModelOverride = model || null;
|
|
31
|
+
if (temp)
|
|
32
|
+
contextTempOverride = parseFloat(temp);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
executionModelOverride = model || null;
|
|
36
|
+
if (temp)
|
|
37
|
+
executionTempOverride = parseFloat(temp);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function clearModelOverrides() {
|
|
41
|
+
contextModelOverride = null;
|
|
42
|
+
contextTempOverride = null;
|
|
43
|
+
executionModelOverride = null;
|
|
44
|
+
executionTempOverride = null;
|
|
45
|
+
}
|
|
7
46
|
// ─── AI Service ──────────────────────────────────────────────────────
|
|
47
|
+
let globalActiveModel = DEFAULT_MODEL;
|
|
48
|
+
export function setGlobalActiveModel(model) {
|
|
49
|
+
globalActiveModel = model;
|
|
50
|
+
}
|
|
51
|
+
export function getGlobalActiveModel() {
|
|
52
|
+
return globalActiveModel;
|
|
53
|
+
}
|
|
54
|
+
let globalLatestUsageMetadata = undefined;
|
|
55
|
+
export function getGlobalLatestUsageMetadata() {
|
|
56
|
+
return globalLatestUsageMetadata;
|
|
57
|
+
}
|
|
8
58
|
const proxyClient = new ProxyClient();
|
|
9
59
|
// ─── History Limits ──────────────────────────────────────────────────
|
|
10
60
|
/** Maximum number of Content entries to keep in the sliding history window. */
|
|
@@ -91,7 +141,7 @@ export class ProxyChatSession {
|
|
|
91
141
|
this.history = this.history.slice(trimCount);
|
|
92
142
|
}
|
|
93
143
|
}
|
|
94
|
-
async sendMessage(message, additionalText, abortSignal) {
|
|
144
|
+
async sendMessage(message, additionalText, abortSignal, onChunk) {
|
|
95
145
|
const idToken = await getAuthorizedIdToken();
|
|
96
146
|
if (!idToken) {
|
|
97
147
|
throw new Error('You are not signed in. Please run `minovative-mind-cli login` first.');
|
|
@@ -102,18 +152,29 @@ export class ProxyChatSession {
|
|
|
102
152
|
newParts = [{ text: truncatePartText(message) }];
|
|
103
153
|
}
|
|
104
154
|
else {
|
|
105
|
-
// It's an array of function responses
|
|
106
|
-
newParts =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
: m.functionResponse.response.output
|
|
155
|
+
// It's an array of function responses
|
|
156
|
+
newParts = [];
|
|
157
|
+
for (const m of message) {
|
|
158
|
+
newParts.push({
|
|
159
|
+
functionResponse: {
|
|
160
|
+
name: m.functionResponse.name,
|
|
161
|
+
response: {
|
|
162
|
+
...m.functionResponse.response,
|
|
163
|
+
output: typeof m.functionResponse.response.output === 'string'
|
|
164
|
+
? truncatePartText(m.functionResponse.response.output)
|
|
165
|
+
: m.functionResponse.response.output,
|
|
166
|
+
},
|
|
114
167
|
},
|
|
115
|
-
}
|
|
116
|
-
|
|
168
|
+
});
|
|
169
|
+
// If the tool execution returned inlineData (e.g. reading a PDF), append it as a sibling Part
|
|
170
|
+
if (m.functionResponse.response.inlineData) {
|
|
171
|
+
newParts.push({
|
|
172
|
+
inlineData: m.functionResponse.response.inlineData
|
|
173
|
+
});
|
|
174
|
+
// Remove it from the textual output payload to avoid schema violations in functionResponse
|
|
175
|
+
delete newParts[newParts.length - 2].functionResponse.response.inlineData;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
117
178
|
}
|
|
118
179
|
if (additionalText) {
|
|
119
180
|
newParts.push({ text: truncatePartText(additionalText) });
|
|
@@ -125,8 +186,20 @@ export class ProxyChatSession {
|
|
|
125
186
|
// Prune old history before sending to keep payload bounded
|
|
126
187
|
this.pruneHistory();
|
|
127
188
|
const effectiveGenerationConfig = { ...this.generationConfig };
|
|
128
|
-
const result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined,
|
|
189
|
+
const result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined, // toolConfig
|
|
190
|
+
this.systemInstruction, effectiveGenerationConfig, onChunk ? { onChunk } : undefined, // streamCallbacks
|
|
191
|
+
abortSignal);
|
|
129
192
|
this.latestUsageMetadata = result.usageMetadata;
|
|
193
|
+
if (result.usageMetadata) {
|
|
194
|
+
globalLatestUsageMetadata = result.usageMetadata;
|
|
195
|
+
}
|
|
196
|
+
// Track token usage metrics
|
|
197
|
+
if (result.usageMetadata) {
|
|
198
|
+
const collector = getMetricCollector();
|
|
199
|
+
if (collector) {
|
|
200
|
+
collector.recordTokenUsage(result.usageMetadata.promptTokens || 0, result.usageMetadata.candidatesTokens || 0, result.usageMetadata.cachedTokens || 0);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
130
203
|
// Append model response to history
|
|
131
204
|
let modelParts = [];
|
|
132
205
|
const allFunctionCalls = [...(result.functionCalls || [])];
|
|
@@ -184,9 +257,12 @@ export class ProxyChatSession {
|
|
|
184
257
|
* Creates a new shared multi-turn chat session via the proxy.
|
|
185
258
|
*/
|
|
186
259
|
export function createSharedChatSession() {
|
|
187
|
-
|
|
260
|
+
let model = executionModelOverride || getGlobalActiveModel();
|
|
261
|
+
if (model === 'auto')
|
|
262
|
+
model = GEMINI_MODELS.FLASH_3_5; // Will be overridden per-turn in executeSingleTurn
|
|
263
|
+
return new ProxyChatSession(model, GENERAL_CHAT_INSTRUCTION, [], {
|
|
188
264
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
189
|
-
temperature: 1,
|
|
265
|
+
temperature: executionTempOverride !== null ? executionTempOverride : 1,
|
|
190
266
|
topP: 0.95,
|
|
191
267
|
topK: 40,
|
|
192
268
|
});
|
|
@@ -199,23 +275,36 @@ export function getGeneralChatConfig() {
|
|
|
199
275
|
}
|
|
200
276
|
export function getPlanExecutionConfig() {
|
|
201
277
|
return {
|
|
202
|
-
systemInstruction: PLAN_EXECUTION_INSTRUCTION,
|
|
203
|
-
tools: [{ functionDeclarations:
|
|
278
|
+
systemInstruction: PLAN_EXECUTION_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()),
|
|
279
|
+
tools: [{ functionDeclarations: getToolDeclarations() }],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export function getPlanModeConfig() {
|
|
283
|
+
return {
|
|
284
|
+
systemInstruction: PLAN_MODE_INSTRUCTION,
|
|
285
|
+
tools: [], // No tools allowed in plan mode
|
|
204
286
|
};
|
|
205
287
|
}
|
|
206
288
|
/**
|
|
207
289
|
* Compresses a large string of text using gemini-3.1-flash-lite.
|
|
208
290
|
* Used for shrinking context payloads to prevent OOM/choking.
|
|
209
291
|
*/
|
|
210
|
-
export async function compressTextUsingFlashLite(text, instruction = 'Summarize the following text concisely. Preserve the most critical technical details, function names, and architecture logic. Keep it under 1500 characters.') {
|
|
211
|
-
if (!text || text.length < 1000)
|
|
292
|
+
export async function compressTextUsingFlashLite(text, instruction = 'Summarize the following text concisely. Preserve the most critical technical details, function names, and architecture logic. Keep it under 1500 characters.', inlineData) {
|
|
293
|
+
if (!text || (text.length < 1000 && !inlineData))
|
|
212
294
|
return text; // Don't compress tiny texts
|
|
213
295
|
try {
|
|
214
296
|
const idToken = await getAuthorizedIdToken();
|
|
215
297
|
if (!idToken)
|
|
216
298
|
return text;
|
|
217
|
-
|
|
218
|
-
|
|
299
|
+
let model = getGlobalActiveModel();
|
|
300
|
+
if (model === 'auto')
|
|
301
|
+
model = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
302
|
+
const parts = [{ text }];
|
|
303
|
+
if (inlineData) {
|
|
304
|
+
parts.push({ inlineData });
|
|
305
|
+
}
|
|
306
|
+
const contents = [{ role: 'user', parts }];
|
|
307
|
+
const result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
|
|
219
308
|
undefined, instruction, { temperature: 0.2 });
|
|
220
309
|
let textPart = '';
|
|
221
310
|
if (result.parts) {
|
|
@@ -236,9 +325,13 @@ export async function compressTextUsingFlashLite(text, instruction = 'Summarize
|
|
|
236
325
|
}
|
|
237
326
|
}
|
|
238
327
|
// ─── Context Agent Service ───────────────────────────────────────────
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Returns the tool declarations for the read-only Context Agent.
|
|
330
|
+
* Extracted as a reusable function so investigation sub-agents can import
|
|
331
|
+
* the same schema without duplicating the declarations.
|
|
332
|
+
*/
|
|
333
|
+
export function getContextToolDeclarations() {
|
|
334
|
+
return [
|
|
242
335
|
{
|
|
243
336
|
functionDeclarations: [
|
|
244
337
|
{
|
|
@@ -271,7 +364,7 @@ export function createContextAgentSession() {
|
|
|
271
364
|
},
|
|
272
365
|
{
|
|
273
366
|
name: 'read_file',
|
|
274
|
-
description: 'Read a single file. Use startLine and endLine to read specific chunks of massive files.',
|
|
367
|
+
description: 'Read a single file. Supports text files and native parsing of .pdf files (including math and diagrams). Use startLine and endLine to read specific chunks of massive text files.',
|
|
275
368
|
parameters: {
|
|
276
369
|
type: 'OBJECT',
|
|
277
370
|
properties: {
|
|
@@ -346,7 +439,8 @@ export function createContextAgentSession() {
|
|
|
346
439
|
"language's native AST parser (e.g., TypeScript compiler API, Python ast module, go/parser). " +
|
|
347
440
|
'The script is executed from a temporary directory and automatically cleaned up after execution. ' +
|
|
348
441
|
'Output should be structured JSON to stdout with name, type, startLine, endLine for each code element. ' +
|
|
349
|
-
'Use the results to make precise read_file calls with exact startLine/endLine instead of guessing.'
|
|
442
|
+
'Use the results to make precise read_file calls with exact startLine/endLine instead of guessing. ' +
|
|
443
|
+
'CRITICAL: Do not use this tool on binary, document, or non-code files (e.g. PDF, image, audio, docx).',
|
|
350
444
|
parameters: {
|
|
351
445
|
type: 'OBJECT',
|
|
352
446
|
properties: {
|
|
@@ -393,26 +487,75 @@ export function createContextAgentSession() {
|
|
|
393
487
|
required: ['query'],
|
|
394
488
|
},
|
|
395
489
|
},
|
|
490
|
+
{
|
|
491
|
+
name: 'semantic_search',
|
|
492
|
+
description: 'Search the codebase by meaning and concept rather than exact text match. ' +
|
|
493
|
+
'Use this when you need to find code related to a concept, pattern, or behavior ' +
|
|
494
|
+
"but don't know the exact variable or function names to grep for. " +
|
|
495
|
+
'Examples: "error handling for API requests", "user authentication flow", ' +
|
|
496
|
+
'"database connection pooling logic". Returns ranked results with file paths, ' +
|
|
497
|
+
'line ranges, and similarity scores.',
|
|
498
|
+
parameters: {
|
|
499
|
+
type: 'OBJECT',
|
|
500
|
+
properties: {
|
|
501
|
+
query: {
|
|
502
|
+
type: 'STRING',
|
|
503
|
+
description: "Natural language description of what you're looking for in the codebase.",
|
|
504
|
+
},
|
|
505
|
+
topK: {
|
|
506
|
+
type: 'NUMBER',
|
|
507
|
+
description: 'Number of results to return. Defaults to 5, maximum 15.',
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
required: ['query'],
|
|
511
|
+
},
|
|
512
|
+
},
|
|
396
513
|
],
|
|
397
514
|
},
|
|
398
515
|
];
|
|
399
|
-
|
|
516
|
+
}
|
|
517
|
+
export function createContextAgentSession() {
|
|
518
|
+
const contextTools = getContextToolDeclarations();
|
|
519
|
+
let model = contextModelOverride || getGlobalActiveModel();
|
|
520
|
+
if (model === 'auto')
|
|
521
|
+
model = GEMINI_MODELS.FLASH_3_5;
|
|
522
|
+
return new ProxyChatSession(model, CONTEXT_SYSTEM_INSTRUCTION.replace('{{MULTI_WORKSPACE_BLOCK}}', getMultiWorkspaceBlock()), contextTools, {
|
|
400
523
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
401
|
-
temperature: 1,
|
|
524
|
+
temperature: contextTempOverride !== null ? contextTempOverride : 1,
|
|
402
525
|
topP: 0.95,
|
|
403
526
|
topK: 40,
|
|
404
527
|
});
|
|
405
528
|
}
|
|
406
529
|
// ─── Intent Router Service ───────────────────────────────────────────
|
|
407
|
-
export const INTENT_ROUTER_MODEL = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
408
530
|
export function createIntentRouterSession() {
|
|
409
|
-
|
|
531
|
+
let model = getGlobalActiveModel();
|
|
532
|
+
if (model === 'auto')
|
|
533
|
+
model = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
534
|
+
return new ProxyChatSession(model, INTENT_ROUTER_SYSTEM_INSTRUCTION, [], // no tools
|
|
535
|
+
{ temperature: 0, responseMimeType: 'application/json' });
|
|
536
|
+
}
|
|
537
|
+
// ─── Execution Complexity Router Service ──────────────────────────────
|
|
538
|
+
export function createExecutionComplexitySession() {
|
|
539
|
+
let model = getGlobalActiveModel();
|
|
540
|
+
if (model === 'auto')
|
|
541
|
+
model = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
542
|
+
return new ProxyChatSession(model, EXECUTION_COMPLEXITY_SYSTEM_INSTRUCTION, [], // no tools
|
|
543
|
+
{ temperature: 0, responseMimeType: 'application/json' });
|
|
544
|
+
}
|
|
545
|
+
// ─── Investigation Complexity Router Service ─────────────────────────
|
|
546
|
+
export function createInvestigationComplexitySession() {
|
|
547
|
+
let model = getGlobalActiveModel();
|
|
548
|
+
if (model === 'auto')
|
|
549
|
+
model = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
550
|
+
return new ProxyChatSession(model, INVESTIGATION_COMPLEXITY_SYSTEM_INSTRUCTION, [], // no tools
|
|
410
551
|
{ temperature: 0, responseMimeType: 'application/json' });
|
|
411
552
|
}
|
|
412
553
|
// ─── Web Search Agent Service ───────────────────────────────────────────
|
|
413
|
-
export const WEB_SEARCH_AGENT_MODEL = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
414
554
|
export function createWebSearchAgentSession() {
|
|
415
|
-
|
|
555
|
+
let model = getGlobalActiveModel();
|
|
556
|
+
if (model === 'auto')
|
|
557
|
+
model = GEMINI_MODELS.FLASH_3_5;
|
|
558
|
+
return new ProxyChatSession(model, WEB_SEARCH_SYSTEM_INSTRUCTION, [{ googleSearch: {} }], {
|
|
416
559
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
417
560
|
temperature: 1,
|
|
418
561
|
topP: 0.95,
|
|
@@ -432,7 +575,10 @@ export async function generateChatTitle(firstMessage) {
|
|
|
432
575
|
return firstMessage.substring(0, maxLength);
|
|
433
576
|
const instruction = "You are a helpful assistant that generates extremely concise chat titles (max 4-5 words) based on a user's first message. Output ONLY the title, no quotes, no markdown, no punctuation.";
|
|
434
577
|
const contents = [{ role: 'user', parts: [{ text: firstMessage.substring(0, 500) }] }];
|
|
435
|
-
|
|
578
|
+
let model = getGlobalActiveModel();
|
|
579
|
+
if (model === 'auto')
|
|
580
|
+
model = GEMINI_MODELS.FLASH_LITE_3_1;
|
|
581
|
+
const result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
|
|
436
582
|
undefined, instruction, { temperature: 0.2 });
|
|
437
583
|
let title = '';
|
|
438
584
|
if (result.parts) {
|
|
@@ -1,31 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a single file modification tracked within a workspace changeset.
|
|
3
|
+
* Captures the state of a file before a change was applied, facilitating reversion.
|
|
4
|
+
*/
|
|
1
5
|
export interface FileChange {
|
|
6
|
+
/**
|
|
7
|
+
* Relative or absolute file path of the affected file.
|
|
8
|
+
*/
|
|
2
9
|
filePath: string;
|
|
10
|
+
/**
|
|
11
|
+
* The original content of the file before any modification in the changeset.
|
|
12
|
+
* A value of `null` indicates the file was newly created and did not exist previously.
|
|
13
|
+
*/
|
|
3
14
|
originalContent: string | null;
|
|
15
|
+
/**
|
|
16
|
+
* The nature of the file operation that occurred.
|
|
17
|
+
* - 'create': The file was newly written to disk.
|
|
18
|
+
* - 'modify': An existing file was updated.
|
|
19
|
+
* - 'delete': An existing file was removed.
|
|
20
|
+
*/
|
|
4
21
|
action: 'create' | 'modify' | 'delete';
|
|
5
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Represents a transactional unit of workspace modifications.
|
|
25
|
+
* Groups related file changes under a shared timestamp and intent description.
|
|
26
|
+
*/
|
|
6
27
|
export interface ChangeSet {
|
|
28
|
+
/**
|
|
29
|
+
* Unix epoch timestamp (in milliseconds) when this changeset was initiated.
|
|
30
|
+
*/
|
|
7
31
|
timestamp: number;
|
|
32
|
+
/**
|
|
33
|
+
* Developer or system-provided description explaining the intent of the changes (e.g. "Edit index.ts").
|
|
34
|
+
*/
|
|
8
35
|
description: string;
|
|
36
|
+
/**
|
|
37
|
+
* Array of individual file modifications tracking the original states prior to this changeset.
|
|
38
|
+
*/
|
|
9
39
|
changes: FileChange[];
|
|
40
|
+
/**
|
|
41
|
+
* The execution outcome status of this changeset.
|
|
42
|
+
* - 'partial': The change operation is still in progress or was interrupted.
|
|
43
|
+
* - 'complete': All planned modifications in the transaction finished successfully.
|
|
44
|
+
*/
|
|
10
45
|
status?: 'complete' | 'partial';
|
|
11
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Service class responsible for tracking, persisting, and reverting file modifications in the workspace.
|
|
49
|
+
* Uses a local project state file (`revert_state.json`) to persist state across CLI invocations.
|
|
50
|
+
*/
|
|
12
51
|
declare class ChangeLogger {
|
|
52
|
+
/**
|
|
53
|
+
* Ordered history stack of committed changesets, oldest first, newest last.
|
|
54
|
+
*/
|
|
13
55
|
private changeStack;
|
|
56
|
+
/**
|
|
57
|
+
* The active changeset currently receiving recorded modifications.
|
|
58
|
+
* Null if no change transaction is actively in progress.
|
|
59
|
+
*/
|
|
14
60
|
private currentChangeSet;
|
|
61
|
+
/**
|
|
62
|
+
* Absolute path to the active workspace root directory.
|
|
63
|
+
*/
|
|
15
64
|
private workspaceRoot;
|
|
65
|
+
/**
|
|
66
|
+
* Maximum number of historical changesets retained in memory and on disk.
|
|
67
|
+
* Older changesets are discarded on save once this limit is exceeded.
|
|
68
|
+
*/
|
|
16
69
|
private readonly MAX_HISTORY;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the change logger is currently enabled.
|
|
72
|
+
*/
|
|
73
|
+
private isEnabled;
|
|
74
|
+
getIsEnabled(): boolean;
|
|
75
|
+
setIsEnabled(enabled: boolean): void;
|
|
76
|
+
/**
|
|
77
|
+
* Initializes the ChangeLogger by setting the workspace root and loading existing
|
|
78
|
+
* history from the local `.minovativemind/revert_state.json` cache file.
|
|
79
|
+
*
|
|
80
|
+
* @param workspaceRoot - The absolute path to the project workspace root.
|
|
81
|
+
*/
|
|
17
82
|
init(workspaceRoot: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* Persists the current committed change stack to the local cache directory.
|
|
85
|
+
* Enforces the `MAX_HISTORY` retention policy by slicing out older entries.
|
|
86
|
+
* Does nothing if the workspace root has not yet been initialized.
|
|
87
|
+
*/
|
|
18
88
|
private saveState;
|
|
89
|
+
/**
|
|
90
|
+
* Retrieves a copy of the active history stack.
|
|
91
|
+
*
|
|
92
|
+
* @returns A shallow copy of the array containing all tracked changesets.
|
|
93
|
+
*/
|
|
19
94
|
getHistory(): ChangeSet[];
|
|
95
|
+
/**
|
|
96
|
+
* Traverses backward through the history stack, popping and collecting changesets
|
|
97
|
+
* until a changeset matching the specified timestamp is encountered (inclusive).
|
|
98
|
+
* Persists the resulting truncated stack after execution.
|
|
99
|
+
*
|
|
100
|
+
* @param timestamp - The unique timestamp identifier of the target changeset to revert back to.
|
|
101
|
+
* @returns An array of popped changesets ordered from newest to oldest.
|
|
102
|
+
*/
|
|
20
103
|
popUntil(timestamp: number): ChangeSet[];
|
|
104
|
+
/**
|
|
105
|
+
* Initiates a new transactional changeset. If a previous changeset was in progress and
|
|
106
|
+
* uncommitted, it is automatically finalized and committed to the history stack first.
|
|
107
|
+
*
|
|
108
|
+
* @param description - Descriptive label summarizing the purpose of the new changeset.
|
|
109
|
+
*/
|
|
21
110
|
startChangeSet(description: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* Records a file change within the active changeset.
|
|
113
|
+
* If no changeset is active, an anonymous default changeset is automatically initialized.
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* Idempotency Guard: If the specified file already has an entry in the current changeset,
|
|
117
|
+
* the original state is preserved. This ensures that multiple successive modifications to
|
|
118
|
+
* the same file within a single transaction map back to the true original state prior to
|
|
119
|
+
* the onset of the transaction.
|
|
120
|
+
*
|
|
121
|
+
* @param filePath - The relative or absolute path of the file being altered.
|
|
122
|
+
* @param originalContent - The text content of the file prior to the change, or null if created.
|
|
123
|
+
* @param action - The classification of the operation ('create', 'modify', or 'delete').
|
|
124
|
+
*/
|
|
22
125
|
logChange(filePath: string, originalContent: string | null, action: 'create' | 'modify' | 'delete'): void;
|
|
126
|
+
/**
|
|
127
|
+
* Marks the status of the active changeset as 'complete', indicating that all scheduled
|
|
128
|
+
* operations within the scope of this transaction finished without interruption.
|
|
129
|
+
*/
|
|
23
130
|
markComplete(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Retrieves a list of file paths that have been modified in the currently active changeset.
|
|
133
|
+
*
|
|
134
|
+
* @returns An array of string file paths, or an empty array if no changeset is active.
|
|
135
|
+
*/
|
|
136
|
+
getChangedFiles(): string[];
|
|
137
|
+
/**
|
|
138
|
+
* Commits the active changeset to the history stack and persists the state to disk,
|
|
139
|
+
* provided that the changeset actually contains one or more recorded file modifications.
|
|
140
|
+
* Resets the active changeset state to null.
|
|
141
|
+
*/
|
|
24
142
|
commitChangeSet(): void;
|
|
143
|
+
/**
|
|
144
|
+
* Retrieves the most recently committed changeset from the history stack without removing it.
|
|
145
|
+
*
|
|
146
|
+
* @returns The latest committed ChangeSet, or null if the stack is currently empty.
|
|
147
|
+
*/
|
|
25
148
|
getLastChangeSet(): ChangeSet | null;
|
|
149
|
+
/**
|
|
150
|
+
* Returns the active, uncommitted changeset currently receiving modifications.
|
|
151
|
+
*
|
|
152
|
+
* @returns The in-progress ChangeSet, or null if no changeset is active.
|
|
153
|
+
*/
|
|
26
154
|
getCurrentChangeSet(): ChangeSet | null;
|
|
155
|
+
/**
|
|
156
|
+
* Removes and returns the most recently committed changeset from the history stack.
|
|
157
|
+
* Persists the newly truncated stack state back to the cache.
|
|
158
|
+
*
|
|
159
|
+
* @returns The removed ChangeSet, or null if no historical changes exist.
|
|
160
|
+
*/
|
|
27
161
|
popLastChangeSet(): ChangeSet | null;
|
|
162
|
+
/**
|
|
163
|
+
* Checks whether the history stack contains any tracked changesets.
|
|
164
|
+
*
|
|
165
|
+
* @returns True if at least one changeset is recorded; false otherwise.
|
|
166
|
+
*/
|
|
28
167
|
hasChanges(): boolean;
|
|
29
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Singleton instance of the ChangeLogger service exported for application-wide tracking.
|
|
171
|
+
*/
|
|
30
172
|
export declare const changeLogger: ChangeLogger;
|
|
31
173
|
export {};
|