minovative-mind-cli 2.8.1 → 2.8.2
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 +1 -0
- package/dist/commands/chat.d.ts +5 -3
- package/dist/commands/chat.js +19 -17
- package/dist/services/agent/inputHandler.js +1 -0
- package/dist/services/agent/slashCommands.d.ts +5 -2
- package/dist/services/agent/slashCommands.js +65 -45
- package/dist/services/agent/types.d.ts +21 -0
- package/dist/services/agent-tools.d.ts +29 -0
- package/dist/services/agent-tools.js +58 -4
- package/dist/services/ai.js +11 -86
- package/dist/services/orchestration/orchestrator.js +9 -9
- package/dist/services/proxyClient.d.ts +14 -0
- package/dist/services/proxyClient.js +184 -5
- package/dist/utils/config.d.ts +2 -2
- package/dist/utils/config.js +2 -2
- package/dist/utils/localSyntaxValidator.js +5 -3
- package/dist/utils/paste.js +19 -1
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,6 +112,7 @@ If you prefer to use your own API key instead of credits, you can configure it v
|
|
|
112
112
|
|
|
113
113
|
| Command | What it does |
|
|
114
114
|
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
115
|
+
| `/config-key` | Configure custom Google AI Studio API key (BYOK mode) |
|
|
115
116
|
| `/models` | Hot-swap the active model |
|
|
116
117
|
| `/plan` | Toggle plan mode to review implementation strategies |
|
|
117
118
|
| `/paste` | Multi-line input mode (cancel with Ctrl+C) |
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -3,13 +3,15 @@ import { Command } from '@oclif/core';
|
|
|
3
3
|
/**
|
|
4
4
|
* @class DefaultCommand
|
|
5
5
|
* @extends Command
|
|
6
|
-
* @description
|
|
7
|
-
* environment initialization, and
|
|
6
|
+
* @description Entry point for the "chat" CLI command. Manages user authentication,
|
|
7
|
+
* environment initialization, workspace setup, update notifications, and launches the interactive AI agent session.
|
|
8
8
|
*/
|
|
9
9
|
export default class DefaultCommand extends Command {
|
|
10
10
|
/**
|
|
11
11
|
* The description displayed in the CLI help output.
|
|
12
|
-
* Details
|
|
12
|
+
* Details all supported slash commands (/config-key, /paste, /plan, /clear, /models,
|
|
13
|
+
* /debug, /auto-approve, /sub-agents, /stats, /revert, /chats, /workspaces, /commit)
|
|
14
|
+
* along with interactive chat controls.
|
|
13
15
|
*/
|
|
14
16
|
static description: string;
|
|
15
17
|
/**
|
package/dist/commands/chat.js
CHANGED
|
@@ -11,31 +11,33 @@ import { updateWorkspaceStatus } from '../services/workspace.js';
|
|
|
11
11
|
/**
|
|
12
12
|
* @class DefaultCommand
|
|
13
13
|
* @extends Command
|
|
14
|
-
* @description
|
|
15
|
-
* environment initialization, and
|
|
14
|
+
* @description Entry point for the "chat" CLI command. Manages user authentication,
|
|
15
|
+
* environment initialization, workspace setup, update notifications, and launches the interactive AI agent session.
|
|
16
16
|
*/
|
|
17
17
|
export default class DefaultCommand extends Command {
|
|
18
18
|
/**
|
|
19
19
|
* The description displayed in the CLI help output.
|
|
20
|
-
* Details
|
|
20
|
+
* Details all supported slash commands (/config-key, /paste, /plan, /clear, /models,
|
|
21
|
+
* /debug, /auto-approve, /sub-agents, /stats, /revert, /chats, /workspaces, /commit)
|
|
22
|
+
* along with interactive chat controls.
|
|
21
23
|
*/
|
|
22
24
|
static description = `Start an interactive AI coding agent session powered by Vertex AI.
|
|
23
25
|
|
|
24
26
|
Inside the chat session, you can use the following commands in the slash menu:
|
|
25
|
-
/
|
|
26
|
-
/
|
|
27
|
-
/
|
|
28
|
-
/clear - Clear conversation history
|
|
29
|
-
/
|
|
30
|
-
/
|
|
31
|
-
/
|
|
32
|
-
/
|
|
33
|
-
/
|
|
34
|
-
/
|
|
35
|
-
/
|
|
36
|
-
/
|
|
37
|
-
/
|
|
38
|
-
|
|
27
|
+
/config-key - BYOK — Configure, clear, or view status of custom Google AI Studio API key
|
|
28
|
+
/paste - Enter multi-line paste mode for long code snippets and prompts
|
|
29
|
+
/plan - Toggle plan mode to review step-by-step implementation strategies
|
|
30
|
+
/clear - Clear conversation history, reset terminal screen, and display logo
|
|
31
|
+
/models - Select or hot-swap the active Gemini model for the session
|
|
32
|
+
/debug - Toggle internal agent telemetry, diagnostic logging, and execution state
|
|
33
|
+
/auto-approve - Toggle automatic execution approval for shell commands and tools
|
|
34
|
+
/sub-agents - Toggle the MMAAK Engine for parallel sub-agent task orchestration
|
|
35
|
+
/stats - View session token usage, credits, active settings, and configurations
|
|
36
|
+
/revert - Undo recent file modifications made by the agent or toggle change logging
|
|
37
|
+
/chats - Resume, list, search, rename, or delete saved chat sessions
|
|
38
|
+
/workspaces - Register and manage cross-repository aliases and active workspace paths
|
|
39
|
+
/commit - Auto-generate Conventional Commit messages from git diff and commit
|
|
40
|
+
|
|
39
41
|
Chat Controls:
|
|
40
42
|
- Multi-line Input: End a line with \\ to continue on the next line
|
|
41
43
|
- Stop/Abort: Type "stop" to immediately interrupt agent generation
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { SlashCommandContext, SlashCommandResult } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Handles all
|
|
4
|
-
*
|
|
3
|
+
* Handles all interactive agent slash commands and updates session control state.
|
|
4
|
+
*
|
|
5
|
+
* @param command - The slash command string entered by the user (e.g. `/paste`, `/clear`, `/models`, `/config-key`).
|
|
6
|
+
* @param context - The execution context containing session state, active chat, input handler, and workspace paths.
|
|
7
|
+
* @returns Promise resolving to a {@link SlashCommandResult} indicating loop continuation, input overrides, or mode toggles.
|
|
5
8
|
*/
|
|
6
9
|
export declare function handleSlashCommand(command: string, context: SlashCommandContext): Promise<SlashCommandResult>;
|
|
@@ -12,56 +12,42 @@ import { printLogo, brandBg, brandFg } from '../../utils/logo.js';
|
|
|
12
12
|
import { readPaste } from '../../utils/paste.js';
|
|
13
13
|
import { setApprovalMode, getApprovalMode, isSubAgentsEnabled, setSubAgentsEnabled } from '../agent-tools.js';
|
|
14
14
|
import { ProxyClient, getAndResetTurnUsage } from '../proxyClient.js';
|
|
15
|
-
import { getAuthorizedIdToken } from '../auth.js';
|
|
16
15
|
import { GEMINI_MODELS, isByokEnabled } from '../../utils/config.js';
|
|
17
16
|
import { loadCredentials, updateCredentialField } from '../../utils/credentialStore.js';
|
|
18
17
|
import { getGlobalActiveModel, setGlobalActiveModel, ProxyChatSession } from '../ai.js';
|
|
18
|
+
/**
|
|
19
|
+
* @file slashCommands.ts
|
|
20
|
+
* @description Interactive slash command handler module for Minovative Mind CLI.
|
|
21
|
+
*
|
|
22
|
+
* Supported slash commands:
|
|
23
|
+
* - `/config-key` : Configure, validate, toggle, or clear Bring Your Own Key (BYOK) Google AI Studio API credentials.
|
|
24
|
+
* - `/paste` : Enter multi-line paste mode using EOF tracking (`Ctrl+D` submission).
|
|
25
|
+
* - `/plan` : Toggle AI step-by-step implementation planning mode.
|
|
26
|
+
* - `/clear` : Clear conversation history, wipe terminal screen, and reset CLI header.
|
|
27
|
+
* - `/models` : Hot-swap the active generative AI model (Gemini 3.1 Pro, Gemini 3.6 Flash, Gemini 3.5 Flash-Lite, Auto routing).
|
|
28
|
+
* - `/debug` : Toggle internal agent telemetry and diagnostic logging.
|
|
29
|
+
* - `/auto-approve`: Toggle automatic confirmation skipping for terminal shell execution commands.
|
|
30
|
+
* - `/sub-agents` : Toggle MMAAK Engine for parallel investigation sub-agent orchestration.
|
|
31
|
+
* - `/stats` : Display session and all-time token usage, credit balances, memory bank stats, and active configurations.
|
|
32
|
+
* - `/revert` : Interactively inspect, revert, or toggle tracking of session file modifications via `changeLogger`.
|
|
33
|
+
* - `/chats` : Interactive management menu to view, resume, rename, delete, or bulk-delete saved chat sessions.
|
|
34
|
+
* - `/workspaces` : Manage primary profiles, external sub-workspaces, and `@alias/` cross-repository path mapping.
|
|
35
|
+
* - `/commit` : Automate Conventional Commit generation using `git diff` analysis via Gemini 3.5 Flash-Lite.
|
|
36
|
+
*/
|
|
19
37
|
const execAsync = promisify(exec);
|
|
20
38
|
/**
|
|
21
|
-
* Handles all
|
|
22
|
-
*
|
|
39
|
+
* Handles all interactive agent slash commands and updates session control state.
|
|
40
|
+
*
|
|
41
|
+
* @param command - The slash command string entered by the user (e.g. `/paste`, `/clear`, `/models`, `/config-key`).
|
|
42
|
+
* @param context - The execution context containing session state, active chat, input handler, and workspace paths.
|
|
43
|
+
* @returns Promise resolving to a {@link SlashCommandResult} indicating loop continuation, input overrides, or mode toggles.
|
|
23
44
|
*/
|
|
24
45
|
export async function handleSlashCommand(command, context) {
|
|
25
46
|
const { chat, inputHandler, workspaceRoot, version, chatSessionState } = context;
|
|
26
47
|
const lowerCommand = command.toLowerCase();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
message: 'BYOK (Bring Your Own Key) Configuration — Google AI Studio keys only',
|
|
31
|
-
options: [
|
|
32
|
-
{ value: 'status', label: 'Status' },
|
|
33
|
-
{ value: 'toggle', label: creds.useByok ? 'Disable BYOK' : 'Enable BYOK' },
|
|
34
|
-
{ value: 'set', label: 'Set API Key' },
|
|
35
|
-
{ value: 'clear', label: 'Clear API Key' },
|
|
36
|
-
{ value: 'cancel', label: 'Cancel' },
|
|
37
|
-
],
|
|
38
|
-
});
|
|
39
|
-
if (action === 'status') {
|
|
40
|
-
const enabled = await isByokEnabled();
|
|
41
|
-
p.log.info(`BYOK Status: ${enabled ? pc.green('Enabled') : pc.red('Disabled')}\n` +
|
|
42
|
-
`API Key: ${creds.geminiApiKey ? pc.green('Set') : pc.red('Not Set')}`);
|
|
43
|
-
}
|
|
44
|
-
else if (action === 'toggle') {
|
|
45
|
-
await updateCredentialField('useByok', !creds.useByok);
|
|
46
|
-
p.log.success(`BYOK ${!creds.useByok ? 'enabled' : 'disabled'}.`);
|
|
47
|
-
}
|
|
48
|
-
else if (action === 'set') {
|
|
49
|
-
const key = await p['text']({
|
|
50
|
-
message: 'Enter your Google AI Studio API Key (aistudio.google.com):',
|
|
51
|
-
validate: (value) => (value ? undefined : 'API Key is required'),
|
|
52
|
-
});
|
|
53
|
-
if (key && typeof key === 'string') {
|
|
54
|
-
await updateCredentialField('geminiApiKey', key);
|
|
55
|
-
p.log.success('API Key updated.');
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
else if (action === 'clear') {
|
|
59
|
-
await updateCredentialField('geminiApiKey', '');
|
|
60
|
-
await updateCredentialField('useByok', false);
|
|
61
|
-
p.log.success('API Key cleared and BYOK disabled.');
|
|
62
|
-
}
|
|
63
|
-
return { shouldContinue: true };
|
|
64
|
-
}
|
|
48
|
+
/**
|
|
49
|
+
* `/paste` - Activates multi-line text capture using readline EOF tracking (`Ctrl+D` on an empty line).
|
|
50
|
+
*/
|
|
65
51
|
if (lowerCommand === '/paste') {
|
|
66
52
|
p.log.info(pc.cyan('Paste mode activated. Paste your text below, then press Ctrl+D on an empty line to submit. (Ctrl+C to cancel)'));
|
|
67
53
|
// Add space at the bottom to prevent terminal UI flickering when the cursor is at the absolute bottom
|
|
@@ -84,6 +70,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
84
70
|
return { shouldContinue: true, isRawPasteMode: false };
|
|
85
71
|
}
|
|
86
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* `/plan` - Toggles step-by-step AI implementation planning mode.
|
|
75
|
+
*/
|
|
87
76
|
if (lowerCommand === '/plan') {
|
|
88
77
|
const newPlanMode = !context.isPlanMode;
|
|
89
78
|
if (newPlanMode) {
|
|
@@ -94,6 +83,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
94
83
|
}
|
|
95
84
|
return { shouldContinue: true, isPlanModeOverride: newPlanMode };
|
|
96
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* `/clear` - Resets chat conversation history, clears the terminal screen, and reprints CLI header.
|
|
88
|
+
*/
|
|
97
89
|
if (lowerCommand === '/clear') {
|
|
98
90
|
chat.clearHistory();
|
|
99
91
|
process.stdout.write('\x1B[2J\x1B[3J\x1B[H'); // Hard clear screen and scrollback
|
|
@@ -105,6 +97,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
105
97
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
106
98
|
return { shouldContinue: true };
|
|
107
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* `/models` - Hot-swaps the active generative AI model or enables dynamic auto-routing.
|
|
102
|
+
*/
|
|
108
103
|
if (lowerCommand === '/models') {
|
|
109
104
|
const currentModel = getGlobalActiveModel();
|
|
110
105
|
const byokEnabled = await isByokEnabled();
|
|
@@ -152,6 +147,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
152
147
|
}
|
|
153
148
|
return { shouldContinue: true };
|
|
154
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* `/debug` - Toggles diagnostic logging and verbose agent telemetry.
|
|
152
|
+
*/
|
|
155
153
|
if (lowerCommand === '/debug') {
|
|
156
154
|
const debugMode = toggleDebugMode();
|
|
157
155
|
if (debugMode) {
|
|
@@ -162,6 +160,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
162
160
|
}
|
|
163
161
|
return { shouldContinue: true };
|
|
164
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* `/auto-approve` - Toggles automatic confirmation for tool shell command execution.
|
|
165
|
+
*/
|
|
165
166
|
if (lowerCommand === '/auto-approve') {
|
|
166
167
|
if (getApprovalMode() === 'skip-all') {
|
|
167
168
|
setApprovalMode('ask');
|
|
@@ -173,6 +174,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
173
174
|
}
|
|
174
175
|
return { shouldContinue: true };
|
|
175
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* `/sub-agents` - Toggles the MMAAK parallel sub-agent orchestration engine.
|
|
179
|
+
*/
|
|
176
180
|
if (lowerCommand === '/sub-agents') {
|
|
177
181
|
if (isSubAgentsEnabled()) {
|
|
178
182
|
setSubAgentsEnabled(false);
|
|
@@ -184,6 +188,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
184
188
|
}
|
|
185
189
|
return { shouldContinue: true };
|
|
186
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* `/stats` - Displays token metrics, credit balances, session history, memory bank stats, and configuration status.
|
|
193
|
+
*/
|
|
187
194
|
if (lowerCommand === '/stats') {
|
|
188
195
|
const latestUsage = context.chatSessionState?.latestUsageMetadata;
|
|
189
196
|
const prevUsage = context.chatSessionState?.previousUsageMetadata;
|
|
@@ -331,6 +338,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
331
338
|
console.log(pc.dim('----------------------------------------\n'));
|
|
332
339
|
return { shouldContinue: true };
|
|
333
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* `/revert` - Interactively restores disk file snapshots or toggles change logging.
|
|
343
|
+
*/
|
|
334
344
|
if (lowerCommand === '/revert') {
|
|
335
345
|
const isEnabled = changeLogger.getIsEnabled();
|
|
336
346
|
const history = changeLogger.getHistory();
|
|
@@ -434,6 +444,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
434
444
|
}
|
|
435
445
|
return { shouldContinue: true };
|
|
436
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* `/chats` - Opens an interactive session manager to view, resume, rename, delete, or bulk-delete chat histories.
|
|
449
|
+
*/
|
|
437
450
|
if (lowerCommand === '/chats') {
|
|
438
451
|
const sessions = chatHistoryService.getSessions() || [];
|
|
439
452
|
const hasSessions = sessions.length > 0;
|
|
@@ -724,6 +737,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
724
737
|
}
|
|
725
738
|
return { shouldContinue: true };
|
|
726
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* `/workspaces` - Manages master profiles and linked external workspaces with cross-repo `@alias/` references.
|
|
742
|
+
*/
|
|
727
743
|
if (lowerCommand === '/workspaces') {
|
|
728
744
|
const { workspaceRegistry } = await import('../workspaceRegistry.js');
|
|
729
745
|
while (true) {
|
|
@@ -967,6 +983,9 @@ export async function handleSlashCommand(command, context) {
|
|
|
967
983
|
}
|
|
968
984
|
return { shouldContinue: true };
|
|
969
985
|
}
|
|
986
|
+
/**
|
|
987
|
+
* `/commit` - Stages changes, generates a Conventional Commit message from `git diff`, and commits.
|
|
988
|
+
*/
|
|
970
989
|
if (lowerCommand === '/commit') {
|
|
971
990
|
const commitSpinner = p.spinner();
|
|
972
991
|
commitSpinner.start('Staging changes and analyzing diff...');
|
|
@@ -1006,6 +1025,9 @@ ${diffOut}
|
|
|
1006
1025
|
}
|
|
1007
1026
|
return { shouldContinue: true };
|
|
1008
1027
|
}
|
|
1028
|
+
/**
|
|
1029
|
+
* `/config-key` - Manages Bring Your Own Key (BYOK) settings, allowing users to set, validate, toggle, or clear API keys.
|
|
1030
|
+
*/
|
|
1009
1031
|
if (lowerCommand === '/config-key') {
|
|
1010
1032
|
const creds = await loadCredentials();
|
|
1011
1033
|
const byokEnabled = !!(creds.useByok && creds.geminiApiKey);
|
|
@@ -1040,11 +1062,9 @@ ${diffOut}
|
|
|
1040
1062
|
const spinner = p.spinner();
|
|
1041
1063
|
spinner.start('Validating API Key...');
|
|
1042
1064
|
try {
|
|
1043
|
-
// Test call to verify
|
|
1065
|
+
// Test call directly with the entered API key to verify it
|
|
1044
1066
|
const client = new ProxyClient();
|
|
1045
|
-
|
|
1046
|
-
// We use a simple prompt to test the key
|
|
1047
|
-
await client.generateFunctionCallViaProxy(idToken, 'gemini-3.5-flash-lite', [{ role: 'user', parts: [{ text: 'ping' }] }], undefined, undefined, 'You are a validator. Respond with "pong".', { maxOutputTokens: 10 });
|
|
1067
|
+
await client.generateViaBYOK(key, 'gemini-3.5-flash-lite', [{ role: 'user', parts: [{ text: 'ping' }] }], undefined, undefined, 'You are a validator. Respond with "pong".', { maxOutputTokens: 10 });
|
|
1048
1068
|
// Reset metrics after validation
|
|
1049
1069
|
getAndResetTurnUsage();
|
|
1050
1070
|
await updateCredentialField('geminiApiKey', key);
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import type { ProxyChatSession } from '../ai.js';
|
|
2
2
|
import type { AsyncInputHandler } from './inputHandler.js';
|
|
3
|
+
/**
|
|
4
|
+
* State tracking container for the active agent operational mode.
|
|
5
|
+
*/
|
|
3
6
|
export interface AgentState {
|
|
7
|
+
/** The target agent mode: 'CHAT' for conversational interactions or 'EXECUTE' for tool/command execution. */
|
|
4
8
|
targetAgent: 'CHAT' | 'EXECUTE';
|
|
5
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Context object provided to slash command handlers containing session handles, terminal state, and metadata.
|
|
12
|
+
*/
|
|
6
13
|
export interface SlashCommandContext {
|
|
14
|
+
/** Active AI session handle supporting message sending and model switching. */
|
|
7
15
|
chat: ProxyChatSession;
|
|
16
|
+
/** Terminal input handler for async non-blocking user prompts. */
|
|
8
17
|
inputHandler: AsyncInputHandler;
|
|
18
|
+
/** Absolute file system path to the active workspace root directory. */
|
|
9
19
|
workspaceRoot: string;
|
|
20
|
+
/** Version string of the running CLI application. */
|
|
10
21
|
version: string;
|
|
22
|
+
/** Flag indicating whether raw paste mode is currently enabled. */
|
|
11
23
|
isRawPasteMode: boolean;
|
|
24
|
+
/** Flag indicating whether step-by-step implementation planning mode is currently active. */
|
|
12
25
|
isPlanMode: boolean;
|
|
26
|
+
/** Session state tracking tokens, credits, usage metadata, and model turn counts. */
|
|
13
27
|
chatSessionState: {
|
|
14
28
|
id: string;
|
|
15
29
|
title: string;
|
|
@@ -22,9 +36,16 @@ export interface SlashCommandContext {
|
|
|
22
36
|
modelUsageCounts?: Record<string, number>;
|
|
23
37
|
};
|
|
24
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Result structure returned by slash command handlers to direct the main event loop.
|
|
41
|
+
*/
|
|
25
42
|
export interface SlashCommandResult {
|
|
43
|
+
/** Indicates whether the main agent loop should continue prompting for user input. */
|
|
26
44
|
shouldContinue: boolean;
|
|
45
|
+
/** Optional input override string to submit directly to the agent (e.g., from `/paste`). */
|
|
27
46
|
userInputOverride?: string;
|
|
47
|
+
/** Optional override flag to enable or disable raw paste mode. */
|
|
28
48
|
isRawPasteMode?: boolean;
|
|
49
|
+
/** Optional override flag to enable or disable implementation planning mode. */
|
|
29
50
|
isPlanModeOverride?: boolean;
|
|
30
51
|
}
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* @description Implements tool declarations, approval state management, ignore rule parser,
|
|
4
4
|
* atomic file operations, search/grep engines, dependency tracer, scratchpad script runner,
|
|
5
5
|
* and central tool dispatcher used by the Minovative Mind AI agents.
|
|
6
|
+
*
|
|
7
|
+
* @module AgentTools
|
|
8
|
+
* @exports toolDeclarations, getToolDeclarations, getApprovalMode, setApprovalMode,
|
|
9
|
+
* isSubAgentsEnabled, setSubAgentsEnabled, consumeSkipOnce, readFile,
|
|
10
|
+
* writeFile, deleteFile, renameFile, modifyFile, listDirectory, runCommand,
|
|
11
|
+
* grepSearch, traceDependencies, findRecentChanges, runDebugScript,
|
|
12
|
+
* executeFuzzProbe, executeHeapDelta, executeBehavioralDrift, executeTool
|
|
6
13
|
*/
|
|
7
14
|
import { type FunctionDeclaration } from '@google/generative-ai';
|
|
8
15
|
/**
|
|
@@ -185,6 +192,13 @@ export declare function findRecentChanges(workspaceRoot: string, dirPath?: strin
|
|
|
185
192
|
export declare function runDebugScript(workspaceRoot: string, language: string, code: string, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
186
193
|
/**
|
|
187
194
|
* Executes a fuzz probing analysis script and formats the resulting pass/fail and crash statistics.
|
|
195
|
+
*
|
|
196
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
197
|
+
* @param code - The fuzz test script or probe code to execute.
|
|
198
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
199
|
+
* @param config - Optional configuration parameters including iterations, maxInputLength, seed, and timeoutMs.
|
|
200
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
201
|
+
* @returns A promise resolving to a {@link ToolResult} containing fuzz run statistics and error summaries.
|
|
188
202
|
*/
|
|
189
203
|
export declare function executeFuzzProbe(workspaceRoot: string, code: string, language?: string, config?: {
|
|
190
204
|
iterations?: number;
|
|
@@ -194,6 +208,13 @@ export declare function executeFuzzProbe(workspaceRoot: string, code: string, la
|
|
|
194
208
|
}, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
195
209
|
/**
|
|
196
210
|
* Executes a heap memory inspection script and formats memory consumption and growth delta metrics.
|
|
211
|
+
*
|
|
212
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
213
|
+
* @param code - The memory inspection script or code snippet to execute.
|
|
214
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
215
|
+
* @param config - Optional configuration parameters including warmupIterations, testIterations, samplingIntervalMs, and timeoutMs.
|
|
216
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
217
|
+
* @returns A promise resolving to a {@link ToolResult} containing memory delta statistics and leak analysis.
|
|
197
218
|
*/
|
|
198
219
|
export declare function executeHeapDelta(workspaceRoot: string, code: string, language?: string, config?: {
|
|
199
220
|
warmupIterations?: number;
|
|
@@ -203,6 +224,14 @@ export declare function executeHeapDelta(workspaceRoot: string, code: string, la
|
|
|
203
224
|
}, abortSignal?: AbortSignal): Promise<ToolResult>;
|
|
204
225
|
/**
|
|
205
226
|
* Executes baseline and candidate scripts, returning output diffs and behavioral drift findings.
|
|
227
|
+
*
|
|
228
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
229
|
+
* @param baselineCode - The baseline implementation script source code.
|
|
230
|
+
* @param candidateCode - The candidate implementation script source code.
|
|
231
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
232
|
+
* @param config - Optional configuration parameters including tolerance, compareKeys, and timeoutMs.
|
|
233
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
234
|
+
* @returns A promise resolving to a {@link ToolResult} containing behavioral drift and diff summaries.
|
|
206
235
|
*/
|
|
207
236
|
export declare function executeBehavioralDrift(workspaceRoot: string, baselineCode: string, candidateCode: string, language?: string, config?: {
|
|
208
237
|
tolerance?: number;
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* @description Implements tool declarations, approval state management, ignore rule parser,
|
|
4
4
|
* atomic file operations, search/grep engines, dependency tracer, scratchpad script runner,
|
|
5
5
|
* and central tool dispatcher used by the Minovative Mind AI agents.
|
|
6
|
+
*
|
|
7
|
+
* @module AgentTools
|
|
8
|
+
* @exports toolDeclarations, getToolDeclarations, getApprovalMode, setApprovalMode,
|
|
9
|
+
* isSubAgentsEnabled, setSubAgentsEnabled, consumeSkipOnce, readFile,
|
|
10
|
+
* writeFile, deleteFile, renameFile, modifyFile, listDirectory, runCommand,
|
|
11
|
+
* grepSearch, traceDependencies, findRecentChanges, runDebugScript,
|
|
12
|
+
* executeFuzzProbe, executeHeapDelta, executeBehavioralDrift, executeTool
|
|
6
13
|
*/
|
|
7
14
|
import { exec } from 'node:child_process';
|
|
8
15
|
import { promises as fs } from 'node:fs';
|
|
@@ -330,7 +337,7 @@ export const toolDeclarations = [
|
|
|
330
337
|
},
|
|
331
338
|
{
|
|
332
339
|
name: 'finish_task',
|
|
333
|
-
description:
|
|
340
|
+
description: "Marks your execution as fully complete. You MUST call this tool when you have finished all tasks on your todo list and completely satisfied the user's request.",
|
|
334
341
|
parameters: {
|
|
335
342
|
type: SchemaType.OBJECT,
|
|
336
343
|
properties: {
|
|
@@ -933,7 +940,11 @@ export async function modifyFile(workspaceRoot, filePath, edits) {
|
|
|
933
940
|
// Provide a preview of the file to help the AI self-correct
|
|
934
941
|
const preview = modified.split('\n').slice(0, 30).join('\n');
|
|
935
942
|
const priorEditsSummary = appliedEdits.length > 0
|
|
936
|
-
? `\nPrior applied edits before failure:\n` +
|
|
943
|
+
? `\nPrior applied edits before failure:\n` +
|
|
944
|
+
appliedEdits
|
|
945
|
+
.map((e) => ` - Edit #${e.index}: Line ${e.line === -1 ? 'N/A' : e.line} (${e.strategy})`)
|
|
946
|
+
.join('\n') +
|
|
947
|
+
'\n'
|
|
937
948
|
: '';
|
|
938
949
|
return {
|
|
939
950
|
output: '',
|
|
@@ -991,7 +1002,10 @@ export async function modifyFile(workspaceRoot, filePath, edits) {
|
|
|
991
1002
|
}
|
|
992
1003
|
if (!success) {
|
|
993
1004
|
const appliedSummary = appliedEdits.length > 0
|
|
994
|
-
? `\nApplied edit details:\n` +
|
|
1005
|
+
? `\nApplied edit details:\n` +
|
|
1006
|
+
appliedEdits
|
|
1007
|
+
.map((e) => ` - Edit #${e.index}: Line ${e.line === -1 ? 'N/A' : e.line} (${e.strategy})`)
|
|
1008
|
+
.join('\n')
|
|
995
1009
|
: '';
|
|
996
1010
|
return {
|
|
997
1011
|
output: '',
|
|
@@ -1033,6 +1047,13 @@ export async function listDirectory(workspaceRoot, dirPath, maxDepth = 3) {
|
|
|
1033
1047
|
const absPath = resolveAndValidatePath(workspaceRoot, dirPath);
|
|
1034
1048
|
const lines = [];
|
|
1035
1049
|
const { ig } = await getIgnoredPaths(workspaceRoot);
|
|
1050
|
+
/**
|
|
1051
|
+
* Recursively walks directory entries to construct an ASCII tree structure.
|
|
1052
|
+
*
|
|
1053
|
+
* @param currentPath - Absolute path to the current directory being traversed.
|
|
1054
|
+
* @param prefix - Current tree branch indentation prefix.
|
|
1055
|
+
* @param depth - Current recursion depth.
|
|
1056
|
+
*/
|
|
1036
1057
|
async function walk(currentPath, prefix, depth) {
|
|
1037
1058
|
if (depth > maxDepth)
|
|
1038
1059
|
return;
|
|
@@ -1146,6 +1167,11 @@ export async function grepSearch(workspaceRoot, pattern, fileGlob, fixedStrings,
|
|
|
1146
1167
|
// Use ignore package to evaluate path globs (e.g. src/**/*.ts)
|
|
1147
1168
|
const globMatcher = fileGlob ? ignore().add(fileGlob) : null;
|
|
1148
1169
|
const results = [];
|
|
1170
|
+
/**
|
|
1171
|
+
* Recursively walks directory entries to search for pattern matches.
|
|
1172
|
+
*
|
|
1173
|
+
* @param dir - Absolute path to the current directory being searched.
|
|
1174
|
+
*/
|
|
1149
1175
|
async function walk(dir) {
|
|
1150
1176
|
if (results.length >= 50)
|
|
1151
1177
|
return;
|
|
@@ -1255,6 +1281,12 @@ export async function findRecentChanges(workspaceRoot, dirPath = '.', minutes =
|
|
|
1255
1281
|
const { ig } = await getIgnoredPaths(workspaceRoot);
|
|
1256
1282
|
const thresholdMs = Date.now() - minutes * 60 * 1000;
|
|
1257
1283
|
const recentFiles = [];
|
|
1284
|
+
/**
|
|
1285
|
+
* Recursively walks directory entries to identify recently modified files.
|
|
1286
|
+
*
|
|
1287
|
+
* @param currentPath - Absolute path to the current directory being checked.
|
|
1288
|
+
* @param depth - Current recursion depth.
|
|
1289
|
+
*/
|
|
1258
1290
|
async function walk(currentPath, depth) {
|
|
1259
1291
|
if (depth > maxDepth)
|
|
1260
1292
|
return;
|
|
@@ -1418,6 +1450,13 @@ export async function runDebugScript(workspaceRoot, language, code, abortSignal)
|
|
|
1418
1450
|
}
|
|
1419
1451
|
/**
|
|
1420
1452
|
* Executes a fuzz probing analysis script and formats the resulting pass/fail and crash statistics.
|
|
1453
|
+
*
|
|
1454
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
1455
|
+
* @param code - The fuzz test script or probe code to execute.
|
|
1456
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
1457
|
+
* @param config - Optional configuration parameters including iterations, maxInputLength, seed, and timeoutMs.
|
|
1458
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
1459
|
+
* @returns A promise resolving to a {@link ToolResult} containing fuzz run statistics and error summaries.
|
|
1421
1460
|
*/
|
|
1422
1461
|
export async function executeFuzzProbe(workspaceRoot, code, language = 'node', config, abortSignal) {
|
|
1423
1462
|
try {
|
|
@@ -1451,6 +1490,13 @@ export async function executeFuzzProbe(workspaceRoot, code, language = 'node', c
|
|
|
1451
1490
|
}
|
|
1452
1491
|
/**
|
|
1453
1492
|
* Executes a heap memory inspection script and formats memory consumption and growth delta metrics.
|
|
1493
|
+
*
|
|
1494
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
1495
|
+
* @param code - The memory inspection script or code snippet to execute.
|
|
1496
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
1497
|
+
* @param config - Optional configuration parameters including warmupIterations, testIterations, samplingIntervalMs, and timeoutMs.
|
|
1498
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
1499
|
+
* @returns A promise resolving to a {@link ToolResult} containing memory delta statistics and leak analysis.
|
|
1454
1500
|
*/
|
|
1455
1501
|
export async function executeHeapDelta(workspaceRoot, code, language = 'node', config, abortSignal) {
|
|
1456
1502
|
try {
|
|
@@ -1487,6 +1533,14 @@ export async function executeHeapDelta(workspaceRoot, code, language = 'node', c
|
|
|
1487
1533
|
}
|
|
1488
1534
|
/**
|
|
1489
1535
|
* Executes baseline and candidate scripts, returning output diffs and behavioral drift findings.
|
|
1536
|
+
*
|
|
1537
|
+
* @param workspaceRoot - Absolute path to the workspace root directory.
|
|
1538
|
+
* @param baselineCode - The baseline implementation script source code.
|
|
1539
|
+
* @param candidateCode - The candidate implementation script source code.
|
|
1540
|
+
* @param language - Runtime environment language (defaults to `'node'`).
|
|
1541
|
+
* @param config - Optional configuration parameters including tolerance, compareKeys, and timeoutMs.
|
|
1542
|
+
* @param abortSignal - Optional AbortSignal to cancel execution.
|
|
1543
|
+
* @returns A promise resolving to a {@link ToolResult} containing behavioral drift and diff summaries.
|
|
1490
1544
|
*/
|
|
1491
1545
|
export async function executeBehavioralDrift(workspaceRoot, baselineCode, candidateCode, language = 'node', config, abortSignal) {
|
|
1492
1546
|
try {
|
|
@@ -1626,7 +1680,7 @@ export async function executeTool(workspaceRoot, toolName, args, abortSignal) {
|
|
|
1626
1680
|
// Normalize common LLM tool alias hallucinations to registered tool names
|
|
1627
1681
|
let normalizedToolName = toolName;
|
|
1628
1682
|
if (normalizedToolName === 'search' || normalizedToolName === 'web_search') {
|
|
1629
|
-
normalizedToolName =
|
|
1683
|
+
normalizedToolName = args.query || args.searchQuery || args.url ? 'perform_web_search' : 'grep_search';
|
|
1630
1684
|
}
|
|
1631
1685
|
else if (normalizedToolName === 'grep' || normalizedToolName === 'search_codebase') {
|
|
1632
1686
|
normalizedToolName = 'grep_search';
|
package/dist/services/ai.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SchemaType, } from '@google/generative-ai';
|
|
2
2
|
import { GEMINI_MODELS, DEFAULT_MODEL, MAX_OUTPUT_TOKENS, isByokEnabled } from '../utils/config.js';
|
|
3
3
|
import { getToolDeclarations } from './agent-tools.js';
|
|
4
4
|
import { getMetricCollector } from './metrics.js';
|
|
@@ -8,7 +8,7 @@ import { readCache, writeCache } from '../utils/projectStorage.js';
|
|
|
8
8
|
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, HISTORY_SUMMARIZER_SYSTEM_INSTRUCTION, } from '../utils/systemPrompts.js';
|
|
9
9
|
import { workspaceRegistry } from './workspaceRegistry.js';
|
|
10
10
|
import { loadCredentials } from '../utils/credentialStore.js';
|
|
11
|
-
import { ProxyClient
|
|
11
|
+
import { ProxyClient } from './proxyClient.js';
|
|
12
12
|
function getMultiWorkspaceBlock() {
|
|
13
13
|
const summary = workspaceRegistry.buildPromptSummary();
|
|
14
14
|
const primaryRoot = process.cwd();
|
|
@@ -232,42 +232,9 @@ export class ProxyChatSession {
|
|
|
232
232
|
let result;
|
|
233
233
|
if (byokEnabled) {
|
|
234
234
|
const creds = await loadCredentials();
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
systemInstruction: this.systemInstruction,
|
|
239
|
-
tools: this.tools,
|
|
240
|
-
});
|
|
241
|
-
const chat = model.startChat({
|
|
242
|
-
history: this.history.slice(0, -1),
|
|
243
|
-
generationConfig: effectiveGenerationConfig,
|
|
244
|
-
});
|
|
245
|
-
const lastMessage = this.history[this.history.length - 1];
|
|
246
|
-
try {
|
|
247
|
-
const response = await chat.sendMessage(lastMessage.parts);
|
|
248
|
-
const responseObj = await response.response;
|
|
249
|
-
result = {
|
|
250
|
-
functionCalls: responseObj.functionCalls(),
|
|
251
|
-
parts: responseObj.candidates?.[0]?.content?.parts,
|
|
252
|
-
usageMetadata: responseObj.usageMetadata,
|
|
253
|
-
};
|
|
254
|
-
if (responseObj.usageMetadata) {
|
|
255
|
-
const collector = getMetricCollector();
|
|
256
|
-
collector?.accumulateUsage(responseObj.usageMetadata);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
debugLog(`Failed to send message via BYOK: ${error}`);
|
|
261
|
-
const errorMessage = error?.message || '';
|
|
262
|
-
if (error?.status === 401 ||
|
|
263
|
-
error?.status === 403 ||
|
|
264
|
-
errorMessage.includes('API_KEY_INVALID') ||
|
|
265
|
-
errorMessage.includes('quota') ||
|
|
266
|
-
errorMessage.includes('PERMISSION_DENIED')) {
|
|
267
|
-
throw new Error('AI_BYOK_ERROR: Your API key or quota is invalid. Please run /config-key to update your settings.');
|
|
268
|
-
}
|
|
269
|
-
throw error;
|
|
270
|
-
}
|
|
235
|
+
result = await proxyClient.generateViaBYOK(creds.geminiApiKey, this.modelName, this.history, this.tools, undefined, // toolConfig
|
|
236
|
+
this.systemInstruction, effectiveGenerationConfig, onChunk ? { onChunk } : undefined, // streamCallbacks
|
|
237
|
+
abortSignal);
|
|
271
238
|
}
|
|
272
239
|
else {
|
|
273
240
|
result = await proxyClient.generateFunctionCallViaProxy(idToken, this.modelName, this.history, this.tools, undefined, // toolConfig
|
|
@@ -390,30 +357,9 @@ export async function compressTextUsingFlashLite(text, instruction = "<directive
|
|
|
390
357
|
const byokEnabled = await isByokEnabled();
|
|
391
358
|
let result;
|
|
392
359
|
if (byokEnabled) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const modelObj = genAI.getGenerativeModel({
|
|
397
|
-
model,
|
|
398
|
-
systemInstruction: instruction,
|
|
399
|
-
});
|
|
400
|
-
const response = await modelObj.generateContent({
|
|
401
|
-
contents: [{ role: 'user', parts }],
|
|
402
|
-
generationConfig: { temperature: 0.2 },
|
|
403
|
-
});
|
|
404
|
-
const responseObj = await response.response;
|
|
405
|
-
result = {
|
|
406
|
-
parts: responseObj.candidates?.[0]?.content?.parts,
|
|
407
|
-
usageMetadata: responseObj.usageMetadata,
|
|
408
|
-
};
|
|
409
|
-
if (responseObj.usageMetadata) {
|
|
410
|
-
accumulateTurnUsage(responseObj.usageMetadata, model);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
catch (error) {
|
|
414
|
-
console.error('BYOK Error:', error.message);
|
|
415
|
-
throw new Error(`BYOK AI Error: ${error.message}`);
|
|
416
|
-
}
|
|
360
|
+
const creds = await loadCredentials();
|
|
361
|
+
result = await proxyClient.generateViaBYOK(creds.geminiApiKey, model, contents, [], // no tools
|
|
362
|
+
undefined, instruction, { temperature: 0.2 });
|
|
417
363
|
}
|
|
418
364
|
else {
|
|
419
365
|
result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
|
|
@@ -680,30 +626,9 @@ export async function generateChatTitle(firstMessage) {
|
|
|
680
626
|
const byokEnabled = await isByokEnabled();
|
|
681
627
|
let result;
|
|
682
628
|
if (byokEnabled) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
const modelObj = genAI.getGenerativeModel({
|
|
687
|
-
model,
|
|
688
|
-
systemInstruction: instruction,
|
|
689
|
-
});
|
|
690
|
-
const response = await modelObj.generateContent({
|
|
691
|
-
contents,
|
|
692
|
-
generationConfig: { temperature: 0.2 },
|
|
693
|
-
});
|
|
694
|
-
const responseObj = await response.response;
|
|
695
|
-
result = {
|
|
696
|
-
parts: responseObj.candidates?.[0]?.content?.parts,
|
|
697
|
-
usageMetadata: responseObj.usageMetadata,
|
|
698
|
-
};
|
|
699
|
-
if (responseObj.usageMetadata) {
|
|
700
|
-
accumulateTurnUsage(responseObj.usageMetadata, model);
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
catch (error) {
|
|
704
|
-
console.error('BYOK Error:', error.message);
|
|
705
|
-
throw new Error(`BYOK AI Error: ${error.message}`);
|
|
706
|
-
}
|
|
629
|
+
const creds = await loadCredentials();
|
|
630
|
+
result = await proxyClient.generateViaBYOK(creds.geminiApiKey, model, contents, [], // no tools
|
|
631
|
+
undefined, instruction, { temperature: 0.2 });
|
|
707
632
|
}
|
|
708
633
|
else {
|
|
709
634
|
result = await proxyClient.generateFunctionCallViaProxy(idToken, model, contents, [], // no tools
|
|
@@ -83,7 +83,7 @@ export class Orchestrator {
|
|
|
83
83
|
* was too simple and should be handled by the main agent loop.
|
|
84
84
|
*/
|
|
85
85
|
async runOrchestration(objective, contextInjection, signal) {
|
|
86
|
-
p.log.step(pc.cyan('Orchestrator: Planning task execution
|
|
86
|
+
p.log.step(pc.cyan('Orchestrator: Planning task execution'));
|
|
87
87
|
// 1. Task Decomposition
|
|
88
88
|
const graph = await this.decomposeTask(objective, contextInjection, signal);
|
|
89
89
|
if (!graph)
|
|
@@ -110,13 +110,13 @@ export class Orchestrator {
|
|
|
110
110
|
p.log.step(pc.magenta(`Starting Wave ${wave.depth + 1} (${wave.taskIds.length} tasks):\n${taskDescriptions}`));
|
|
111
111
|
const s = p.spinner();
|
|
112
112
|
this.inputHandler.setSpinner(s);
|
|
113
|
-
s.start(`Executing Wave ${wave.depth + 1}
|
|
113
|
+
s.start(`Executing Wave ${wave.depth + 1}`);
|
|
114
114
|
const agentStatuses = new Map();
|
|
115
115
|
const updateSpinner = () => {
|
|
116
116
|
const statuses = Array.from(agentStatuses.entries())
|
|
117
117
|
.map(([id, status]) => `${pc.cyan(id)}: ${pc.dim(status)}`)
|
|
118
118
|
.join(' │ ');
|
|
119
|
-
s.message(statuses || `Executing Wave ${wave.depth + 1}
|
|
119
|
+
s.message(statuses || `Executing Wave ${wave.depth + 1}`);
|
|
120
120
|
};
|
|
121
121
|
// Limit to 2 concurrent sub-agents to avoid Vertex AI RESOURCE_EXHAUSTED
|
|
122
122
|
const results = [];
|
|
@@ -127,7 +127,7 @@ export class Orchestrator {
|
|
|
127
127
|
const wavePromises = chunk.map((taskId) => {
|
|
128
128
|
const taskDef = graph.tasks.find((t) => t.id === taskId);
|
|
129
129
|
const globalContext = `Objective:\n${objective}\n\nContext:\n${contextInjection}`;
|
|
130
|
-
agentStatuses.set(taskDef.id, 'Starting
|
|
130
|
+
agentStatuses.set(taskDef.id, 'Starting');
|
|
131
131
|
updateSpinner();
|
|
132
132
|
const onToolCall = (msg) => {
|
|
133
133
|
const formattedLog = `${pc.dim(`[${taskDef.id}]`)} ${msg}`;
|
|
@@ -151,7 +151,7 @@ export class Orchestrator {
|
|
|
151
151
|
const successful = results.filter((r) => r.success).length;
|
|
152
152
|
s.stop(`Wave ${wave.depth + 1} completed: ${successful}/${wave.taskIds.length} tasks succeeded`);
|
|
153
153
|
if (toolLogs.length > 0) {
|
|
154
|
-
toolLogs.forEach(log => p.log.step(log));
|
|
154
|
+
toolLogs.forEach((log) => p.log.step(log));
|
|
155
155
|
}
|
|
156
156
|
// Post-wave evaluation
|
|
157
157
|
const failedCount = results.filter((r) => !r.success).length;
|
|
@@ -200,7 +200,7 @@ export class Orchestrator {
|
|
|
200
200
|
}
|
|
201
201
|
else {
|
|
202
202
|
// JSON parsing error or InvalidDependencyError
|
|
203
|
-
debugLog(`PM Agent generated invalid graph: ${err.message}. Retrying
|
|
203
|
+
debugLog(`PM Agent generated invalid graph: ${err.message}. Retrying`);
|
|
204
204
|
result = await this.pmChat.sendMessage(`Invalid JSON or missing dependency ID: ${err.message}. Please fix.`, undefined, signal);
|
|
205
205
|
if (signal.aborted)
|
|
206
206
|
return null;
|
|
@@ -246,7 +246,7 @@ export class Orchestrator {
|
|
|
246
246
|
* Final reconciliation phase after all waves complete.
|
|
247
247
|
*/
|
|
248
248
|
async reconcile(graph) {
|
|
249
|
-
p.log.step(pc.cyan('Orchestrator: Reconciling results
|
|
249
|
+
p.log.step(pc.cyan('Orchestrator: Reconciling results'));
|
|
250
250
|
const stats = this.bus.getStats();
|
|
251
251
|
let totalTokens = 0;
|
|
252
252
|
let inputTokens = 0;
|
|
@@ -259,10 +259,10 @@ export class Orchestrator {
|
|
|
259
259
|
outputTokens += res.outputTokens || 0;
|
|
260
260
|
if (!res.success)
|
|
261
261
|
failedTasks++;
|
|
262
|
-
debugLog(`Task ${taskId} summary: ${res.summary.substring(0, 100)}
|
|
262
|
+
debugLog(`Task ${taskId} summary: ${res.summary.substring(0, 100)}`);
|
|
263
263
|
rawSummaryData += `Task: ${taskId} | Status: ${res.success ? 'Success' : 'Failed'}\nChanges:\n${res.summary}\n\n`;
|
|
264
264
|
}
|
|
265
|
-
p.log.step(pc.cyan('Orchestrator: Synthesizing final changes overview
|
|
265
|
+
p.log.step(pc.cyan('Orchestrator: Synthesizing final changes overview'));
|
|
266
266
|
let finalSummary = '';
|
|
267
267
|
try {
|
|
268
268
|
const payloadWithContext = `<original_request>\n${graph.objective}\n</original_request>\n\n<task_summaries>\n${rawSummaryData}\n</task_summaries>`;
|
|
@@ -72,4 +72,18 @@ export declare class ProxyClient {
|
|
|
72
72
|
usageMetadata?: ProxyUsageMetadata;
|
|
73
73
|
groundingMetadata?: any;
|
|
74
74
|
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Generates text, thoughts, or function calls directly via Google's official Gemini REST API (BYOK mode).
|
|
77
|
+
* Ensures identical return structure and standard role mapping parity with proxy mode.
|
|
78
|
+
*/
|
|
79
|
+
generateViaBYOK(apiKey: string, modelName: string, contents: Content[], tools?: Tool[], toolConfig?: ToolConfig, systemInstruction?: string | Content, generationConfig?: any, streamCallbacks?: {
|
|
80
|
+
onChunk: (chunk: string) => void;
|
|
81
|
+
}, abortSignal?: AbortSignal): Promise<{
|
|
82
|
+
functionCall: FunctionCall | null;
|
|
83
|
+
functionCalls: FunctionCall[];
|
|
84
|
+
thought?: string;
|
|
85
|
+
parts?: any[];
|
|
86
|
+
usageMetadata?: ProxyUsageMetadata;
|
|
87
|
+
groundingMetadata?: any;
|
|
88
|
+
}>;
|
|
75
89
|
}
|
|
@@ -114,11 +114,11 @@ export class ProxyClient {
|
|
|
114
114
|
signal: abortSignal,
|
|
115
115
|
});
|
|
116
116
|
debugLog(`Proxy Request to ${modelName} complete. Status: ${response.status} ${response.statusText}`);
|
|
117
|
-
if ((response.status === 429 || response.status === 503) && attempt < MAX_RETRIES) {
|
|
117
|
+
if ((response.status === 429 || response.status === 503 || response.status === 502 || response.status === 500 || response.status === 504) && attempt < MAX_RETRIES) {
|
|
118
118
|
const exponentialDelay = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * Math.pow(2, attempt));
|
|
119
|
-
const delayTime = Math.round(exponentialDelay * (0
|
|
119
|
+
const delayTime = Math.round(exponentialDelay * (1.0 + Math.random() * 0.5));
|
|
120
120
|
process.stdout.write('\n');
|
|
121
|
-
console.warn(`
|
|
121
|
+
console.warn(`Server error or rate limit hit (${response.status}). Retrying in ${(delayTime / 1000).toFixed(1)}s... (Attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
122
122
|
await delay(delayTime, abortSignal);
|
|
123
123
|
attempt++;
|
|
124
124
|
continue;
|
|
@@ -232,14 +232,18 @@ export class ProxyClient {
|
|
|
232
232
|
}
|
|
233
233
|
catch (streamError) {
|
|
234
234
|
if (streamError.message?.includes('429') ||
|
|
235
|
+
streamError.message?.includes('502') ||
|
|
235
236
|
streamError.message?.includes('503') ||
|
|
237
|
+
streamError.message?.includes('500') ||
|
|
238
|
+
streamError.message?.includes('504') ||
|
|
239
|
+
streamError.message?.includes('Bad Gateway') ||
|
|
236
240
|
streamError.message?.includes('RESOURCE_EXHAUSTED') ||
|
|
237
241
|
streamError.message?.includes('Too Many Requests')) {
|
|
238
242
|
if (attempt < MAX_RETRIES) {
|
|
239
243
|
const exponentialDelay = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * Math.pow(2, attempt));
|
|
240
|
-
const delayTime = Math.round(exponentialDelay * (0
|
|
244
|
+
const delayTime = Math.round(exponentialDelay * (1.0 + Math.random() * 0.5));
|
|
241
245
|
process.stdout.write('\n');
|
|
242
|
-
console.warn(`
|
|
246
|
+
console.warn(`Server error or rate limit hit during stream. Retrying in ${(delayTime / 1000).toFixed(1)}s... (Attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
243
247
|
await delay(delayTime, abortSignal);
|
|
244
248
|
attempt++;
|
|
245
249
|
continue retryLoop;
|
|
@@ -260,4 +264,179 @@ export class ProxyClient {
|
|
|
260
264
|
};
|
|
261
265
|
}
|
|
262
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Generates text, thoughts, or function calls directly via Google's official Gemini REST API (BYOK mode).
|
|
269
|
+
* Ensures identical return structure and standard role mapping parity with proxy mode.
|
|
270
|
+
*/
|
|
271
|
+
async generateViaBYOK(apiKey, modelName, contents, tools, toolConfig, systemInstruction, generationConfig, streamCallbacks, abortSignal) {
|
|
272
|
+
const isStreaming = Boolean(streamCallbacks?.onChunk);
|
|
273
|
+
const endpoint = isStreaming ? 'streamGenerateContent?alt=sse&key=' : 'generateContent?key=';
|
|
274
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(modelName)}:${endpoint}${encodeURIComponent(apiKey)}`;
|
|
275
|
+
const formattedSystemInstruction = typeof systemInstruction === 'string' ? { parts: [{ text: systemInstruction }] } : systemInstruction;
|
|
276
|
+
const payload = { contents };
|
|
277
|
+
if (tools && tools.length > 0)
|
|
278
|
+
payload.tools = tools;
|
|
279
|
+
if (toolConfig)
|
|
280
|
+
payload.toolConfig = toolConfig;
|
|
281
|
+
if (formattedSystemInstruction)
|
|
282
|
+
payload.systemInstruction = formattedSystemInstruction;
|
|
283
|
+
if (generationConfig)
|
|
284
|
+
payload.generationConfig = generationConfig;
|
|
285
|
+
const MAX_RETRIES = 5;
|
|
286
|
+
const BASE_DELAY_MS = 2000;
|
|
287
|
+
const MAX_DELAY_MS = 30000;
|
|
288
|
+
let attempt = 0;
|
|
289
|
+
while (true) {
|
|
290
|
+
const response = await fetch(url, {
|
|
291
|
+
method: 'POST',
|
|
292
|
+
headers: { 'Content-Type': 'application/json' },
|
|
293
|
+
body: JSON.stringify(payload),
|
|
294
|
+
signal: abortSignal,
|
|
295
|
+
});
|
|
296
|
+
debugLog(`BYOK Request to ${modelName} complete. Status: ${response.status} ${response.statusText}`);
|
|
297
|
+
if ((response.status === 429 ||
|
|
298
|
+
response.status === 503 ||
|
|
299
|
+
response.status === 502 ||
|
|
300
|
+
response.status === 500 ||
|
|
301
|
+
response.status === 504) &&
|
|
302
|
+
attempt < MAX_RETRIES) {
|
|
303
|
+
const exponentialDelay = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * Math.pow(2, attempt));
|
|
304
|
+
const delayTime = Math.round(exponentialDelay * (1.0 + Math.random() * 0.5));
|
|
305
|
+
process.stdout.write('\n');
|
|
306
|
+
console.warn(`Server error or rate limit hit (${response.status}). Retrying in ${(delayTime / 1000).toFixed(1)}s... (Attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
307
|
+
await delay(delayTime, abortSignal);
|
|
308
|
+
attempt++;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
let errorData = {};
|
|
313
|
+
try {
|
|
314
|
+
errorData = await response.json();
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// ignore parsing error
|
|
318
|
+
}
|
|
319
|
+
const errorMsg = errorData.error?.message || response.statusText;
|
|
320
|
+
if (response.status === 400 ||
|
|
321
|
+
response.status === 401 ||
|
|
322
|
+
response.status === 403 ||
|
|
323
|
+
errorMsg.includes('API_KEY_INVALID') ||
|
|
324
|
+
errorMsg.includes('quota') ||
|
|
325
|
+
errorMsg.includes('PERMISSION_DENIED')) {
|
|
326
|
+
throw new Error('AI_BYOK_ERROR: Your API key or quota is invalid. Please run /config-key to update your settings.');
|
|
327
|
+
}
|
|
328
|
+
throw new Error(`BYOK API Error ${response.status}: ${errorMsg}`);
|
|
329
|
+
}
|
|
330
|
+
let functionCall = null;
|
|
331
|
+
const functionCalls = [];
|
|
332
|
+
let thought = '';
|
|
333
|
+
let parts = undefined;
|
|
334
|
+
let usageMetadata = undefined;
|
|
335
|
+
let groundingMetadata = undefined;
|
|
336
|
+
if (isStreaming) {
|
|
337
|
+
if (!response.body)
|
|
338
|
+
throw new Error('No response body received from BYOK API endpoint');
|
|
339
|
+
const reader = response.body.getReader();
|
|
340
|
+
const decoder = new TextDecoder();
|
|
341
|
+
let buffer = '';
|
|
342
|
+
try {
|
|
343
|
+
while (true) {
|
|
344
|
+
const { done, value } = await reader.read();
|
|
345
|
+
if (done)
|
|
346
|
+
break;
|
|
347
|
+
buffer += decoder.decode(value, { stream: true });
|
|
348
|
+
const lines = buffer.split('\n\n');
|
|
349
|
+
buffer = lines.pop() || '';
|
|
350
|
+
for (const line of lines) {
|
|
351
|
+
if (!line.startsWith('data: '))
|
|
352
|
+
continue;
|
|
353
|
+
const dataStr = line.slice(6).trim();
|
|
354
|
+
if (!dataStr)
|
|
355
|
+
continue;
|
|
356
|
+
try {
|
|
357
|
+
const data = JSON.parse(dataStr);
|
|
358
|
+
const candidate = data.candidates?.[0];
|
|
359
|
+
if (candidate?.content?.parts) {
|
|
360
|
+
parts = candidate.content.parts;
|
|
361
|
+
for (const part of candidate.content.parts) {
|
|
362
|
+
if (part.text) {
|
|
363
|
+
thought += part.text;
|
|
364
|
+
if (streamCallbacks?.onChunk)
|
|
365
|
+
streamCallbacks.onChunk(part.text);
|
|
366
|
+
}
|
|
367
|
+
if (part.functionCall) {
|
|
368
|
+
functionCall = part.functionCall;
|
|
369
|
+
functionCalls.push(part.functionCall);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (candidate?.groundingMetadata) {
|
|
374
|
+
groundingMetadata = candidate.groundingMetadata;
|
|
375
|
+
}
|
|
376
|
+
if (data.usageMetadata) {
|
|
377
|
+
const pTokens = data.usageMetadata.promptTokenCount || 0;
|
|
378
|
+
const cTokens = data.usageMetadata.candidatesTokenCount || 0;
|
|
379
|
+
const cachedTokens = data.usageMetadata.cachedContentTokenCount || 0;
|
|
380
|
+
usageMetadata = {
|
|
381
|
+
promptTokens: pTokens,
|
|
382
|
+
candidatesTokens: cTokens,
|
|
383
|
+
cachedTokens: cachedTokens,
|
|
384
|
+
creditsUsed: 0,
|
|
385
|
+
remainingBalance: 0,
|
|
386
|
+
};
|
|
387
|
+
accumulateTurnUsage(data.usageMetadata, modelName);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (parseError) {
|
|
391
|
+
debugLog(`Failed to parse BYOK SSE data: ${dataStr} - Error: ${parseError.message || parseError}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
finally {
|
|
397
|
+
reader.releaseLock();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
const data = await response.json();
|
|
402
|
+
const candidate = data.candidates?.[0];
|
|
403
|
+
if (candidate?.content?.parts) {
|
|
404
|
+
parts = candidate.content.parts;
|
|
405
|
+
for (const part of candidate.content.parts) {
|
|
406
|
+
if (part.text) {
|
|
407
|
+
thought += part.text;
|
|
408
|
+
}
|
|
409
|
+
if (part.functionCall) {
|
|
410
|
+
functionCall = part.functionCall;
|
|
411
|
+
functionCalls.push(part.functionCall);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (candidate?.groundingMetadata) {
|
|
416
|
+
groundingMetadata = candidate.groundingMetadata;
|
|
417
|
+
}
|
|
418
|
+
if (data.usageMetadata) {
|
|
419
|
+
const pTokens = data.usageMetadata.promptTokenCount || 0;
|
|
420
|
+
const cTokens = data.usageMetadata.candidatesTokenCount || 0;
|
|
421
|
+
const cachedTokens = data.usageMetadata.cachedContentTokenCount || 0;
|
|
422
|
+
usageMetadata = {
|
|
423
|
+
promptTokens: pTokens,
|
|
424
|
+
candidatesTokens: cTokens,
|
|
425
|
+
cachedTokens: cachedTokens,
|
|
426
|
+
creditsUsed: 0,
|
|
427
|
+
remainingBalance: 0,
|
|
428
|
+
};
|
|
429
|
+
accumulateTurnUsage(data.usageMetadata, modelName);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
functionCall,
|
|
434
|
+
functionCalls,
|
|
435
|
+
thought: thought.trim(),
|
|
436
|
+
parts,
|
|
437
|
+
usageMetadata,
|
|
438
|
+
groundingMetadata,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
263
442
|
}
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -32,9 +32,9 @@ export declare const MAX_OUTPUT_TOKENS = 60000;
|
|
|
32
32
|
*/
|
|
33
33
|
export declare const TPM_COOLING_DELAYS: {
|
|
34
34
|
/** Pause before running initial intent routing between turns */
|
|
35
|
-
readonly INTER_TURN_MS:
|
|
35
|
+
readonly INTER_TURN_MS: 3000;
|
|
36
36
|
/** Pause before dispatching parallel sub-agent investigations simultaneously */
|
|
37
|
-
readonly PARALLEL_DISPATCH_MS:
|
|
37
|
+
readonly PARALLEL_DISPATCH_MS: 3000;
|
|
38
38
|
/** Pause after context gathering completes before starting the execution stream */
|
|
39
39
|
readonly POST_INVESTIGATION_MS: 3000;
|
|
40
40
|
};
|
package/dist/utils/config.js
CHANGED
|
@@ -32,9 +32,9 @@ export const MAX_OUTPUT_TOKENS = 60_000;
|
|
|
32
32
|
*/
|
|
33
33
|
export const TPM_COOLING_DELAYS = {
|
|
34
34
|
/** Pause before running initial intent routing between turns */
|
|
35
|
-
INTER_TURN_MS:
|
|
35
|
+
INTER_TURN_MS: 3000,
|
|
36
36
|
/** Pause before dispatching parallel sub-agent investigations simultaneously */
|
|
37
|
-
PARALLEL_DISPATCH_MS:
|
|
37
|
+
PARALLEL_DISPATCH_MS: 3000,
|
|
38
38
|
/** Pause after context gathering completes before starting the execution stream */
|
|
39
39
|
POST_INVESTIGATION_MS: 3000,
|
|
40
40
|
};
|
|
@@ -115,7 +115,6 @@ export function localValidate(filePath, content) {
|
|
|
115
115
|
'?',
|
|
116
116
|
':',
|
|
117
117
|
'<',
|
|
118
|
-
'>',
|
|
119
118
|
'/',
|
|
120
119
|
'=>',
|
|
121
120
|
'${',
|
|
@@ -227,10 +226,13 @@ export function localValidate(filePath, content) {
|
|
|
227
226
|
continue;
|
|
228
227
|
}
|
|
229
228
|
// Check for regex literal start
|
|
230
|
-
if (isJsTs && char === '/') {
|
|
229
|
+
if (isJsTs && char === '/' && nextChar !== '>') {
|
|
231
230
|
// Determine if '/' starts a regex or is a division operator
|
|
232
231
|
const prevToken = currentWord || lastToken;
|
|
233
|
-
const isExpr =
|
|
232
|
+
const isExpr = prevToken !== '<' &&
|
|
233
|
+
prevToken !== '}' &&
|
|
234
|
+
prevToken !== '>' &&
|
|
235
|
+
(!prevToken || EXPR_KEYWORDS.has(prevToken) || EXPR_PUNCT.has(prevToken));
|
|
234
236
|
if (isExpr) {
|
|
235
237
|
inRegex = true;
|
|
236
238
|
inRegexCharClass = false;
|
package/dist/utils/paste.js
CHANGED
|
@@ -22,24 +22,42 @@ import * as readline from 'node:readline';
|
|
|
22
22
|
*/
|
|
23
23
|
export async function readPaste() {
|
|
24
24
|
return new Promise((resolve) => {
|
|
25
|
+
if (process.stdin.isTTY) {
|
|
26
|
+
process.stdin.setRawMode(false);
|
|
27
|
+
}
|
|
28
|
+
process.stdin.resume();
|
|
25
29
|
const rl = readline.createInterface({
|
|
26
30
|
input: process.stdin,
|
|
27
31
|
output: process.stdout,
|
|
28
32
|
terminal: true,
|
|
29
33
|
});
|
|
34
|
+
rl.setPrompt('');
|
|
35
|
+
rl.prompt();
|
|
30
36
|
const content = [];
|
|
31
37
|
let isCanceled = false;
|
|
38
|
+
let cleanedUp = false;
|
|
39
|
+
const cleanup = () => {
|
|
40
|
+
if (cleanedUp)
|
|
41
|
+
return;
|
|
42
|
+
cleanedUp = true;
|
|
43
|
+
rl.close();
|
|
44
|
+
if (process.stdin.isTTY) {
|
|
45
|
+
process.stdin.setRawMode(false);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
32
48
|
rl.on('line', (line) => {
|
|
33
49
|
content.push(line);
|
|
50
|
+
rl.prompt();
|
|
34
51
|
});
|
|
35
52
|
rl.on('close', () => {
|
|
53
|
+
cleanup();
|
|
36
54
|
if (!isCanceled) {
|
|
37
55
|
resolve(content.join('\n').trim());
|
|
38
56
|
}
|
|
39
57
|
});
|
|
40
58
|
rl.on('SIGINT', () => {
|
|
41
59
|
isCanceled = true;
|
|
42
|
-
|
|
60
|
+
cleanup();
|
|
43
61
|
resolve(null);
|
|
44
62
|
});
|
|
45
63
|
});
|
package/oclif.manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"chat": {
|
|
4
4
|
"aliases": [],
|
|
5
5
|
"args": {},
|
|
6
|
-
"description": "Start an interactive AI coding agent session powered by Vertex AI.\n\nInside the chat session, you can use the following commands in the slash menu:\n /
|
|
6
|
+
"description": "Start an interactive AI coding agent session powered by Vertex AI.\n\nInside the chat session, you can use the following commands in the slash menu:\n /config-key - BYOK — Configure, clear, or view status of custom Google AI Studio API key\n /paste - Enter multi-line paste mode for long code snippets and prompts\n /plan - Toggle plan mode to review step-by-step implementation strategies\n /clear - Clear conversation history, reset terminal screen, and display logo\n /models - Select or hot-swap the active Gemini model for the session\n /debug - Toggle internal agent telemetry, diagnostic logging, and execution state\n /auto-approve - Toggle automatic execution approval for shell commands and tools\n /sub-agents - Toggle the MMAAK Engine for parallel sub-agent task orchestration\n /stats - View session token usage, credits, active settings, and configurations\n /revert - Undo recent file modifications made by the agent or toggle change logging\n /chats - Resume, list, search, rename, or delete saved chat sessions\n /workspaces - Register and manage cross-repository aliases and active workspace paths\n /commit - Auto-generate Conventional Commit messages from git diff and commit\n\nChat Controls:\n - Multi-line Input: End a line with \\ to continue on the next line\n - Stop/Abort: Type \"stop\" to immediately interrupt agent generation\n - Exit Session: Type \"exit\" or \"quit\" to end the agent session",
|
|
7
7
|
"examples": [
|
|
8
8
|
"<%= config.bin %> chat",
|
|
9
9
|
"<%= config.bin %> chat --help"
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
]
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
|
-
"version": "2.8.
|
|
68
|
+
"version": "2.8.2"
|
|
69
69
|
}
|
package/package.json
CHANGED