minovative-mind-cli 2.13.5 → 2.14.1
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 +104 -39
- package/dist/services/agent/slashCommands.js +57 -8
- package/dist/services/agent/syntaxAgent.js +13 -0
- package/dist/services/agent-tools.d.ts +1 -1
- package/dist/services/agent-tools.js +2 -2
- package/dist/services/agent.js +119 -7
- package/dist/services/ai.d.ts +19 -0
- package/dist/services/ai.js +97 -5
- package/dist/services/contextAgent.js +23 -0
- package/dist/services/investigationComplexity.js +1 -1
- package/dist/services/mentionEngine.d.ts +385 -0
- package/dist/services/mentionEngine.js +1395 -0
- package/dist/services/orchestration/investigationAgent.js +6 -2
- package/dist/services/orchestration/messageBus.d.ts +26 -3
- package/dist/services/orchestration/messageBus.js +204 -14
- package/dist/services/orchestration/orchestrator.js +4 -0
- package/dist/services/orchestration/scopedTools.js +16 -2
- package/dist/services/orchestration/subAgent.js +14 -2
- package/dist/services/proxyClient.d.ts +38 -2
- package/dist/services/proxyClient.js +42 -24
- package/dist/utils/config.d.ts +75 -0
- package/dist/utils/config.js +93 -0
- package/dist/utils/contextPrompts.d.ts +28 -4
- package/dist/utils/contextPrompts.js +70 -1
- package/dist/utils/historyPrompt.d.ts +166 -7
- package/dist/utils/historyPrompt.js +775 -30
- package/dist/utils/symbolExtractor.d.ts +111 -8
- package/dist/utils/symbolExtractor.js +616 -64
- package/dist/utils/systemPrompts.d.ts +3 -3
- package/dist/utils/systemPrompts.js +5 -3
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -2,19 +2,29 @@ import { debugLog, isDebugOn } from '../utils/logger.js';
|
|
|
2
2
|
import { GEMINI_MODELS } from '../utils/config.js';
|
|
3
3
|
import { getMetricCollector } from './metrics.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* serverless Gemini content generation proxy.
|
|
10
|
-
*
|
|
11
|
-
* Core Capabilities:
|
|
12
|
-
* - Server-Sent Events (SSE) parsing for thoughts, text, and function calls.
|
|
13
|
-
* - Secure Authentication handling (Firebase ID Tokens).
|
|
14
|
-
* - Real-time stream-callback piping for instant responses.
|
|
15
|
-
* - Accurate token usage, credit consumption, and grounding metadata parsing.
|
|
16
|
-
* ============================================================================
|
|
5
|
+
* Normalizes generation configuration across Proxy and BYOK endpoints.
|
|
6
|
+
* Strips 'MINIMAL' thinking level since Gemini 3.x models use default thinking
|
|
7
|
+
* behavior when no explicit thinking level is provided, preventing 400 Bad Request
|
|
8
|
+
* rejections from Google's Generative Language API.
|
|
17
9
|
*/
|
|
10
|
+
export function normalizeGenerationConfig(config) {
|
|
11
|
+
if (!config)
|
|
12
|
+
return undefined;
|
|
13
|
+
const normalized = { ...config };
|
|
14
|
+
if (normalized.thinkingConfig) {
|
|
15
|
+
const thinkingConfig = { ...normalized.thinkingConfig };
|
|
16
|
+
if (thinkingConfig.thinkingLevel === 'MINIMAL') {
|
|
17
|
+
delete thinkingConfig.thinkingLevel;
|
|
18
|
+
}
|
|
19
|
+
if (Object.keys(thinkingConfig).length === 0) {
|
|
20
|
+
delete normalized.thinkingConfig;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
normalized.thinkingConfig = thinkingConfig;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return normalized;
|
|
27
|
+
}
|
|
18
28
|
/**
|
|
19
29
|
* Helper to pause execution for a specified duration, respecting abort signals.
|
|
20
30
|
*/
|
|
@@ -106,23 +116,28 @@ export class ProxyClient {
|
|
|
106
116
|
err.name = 'AbortError';
|
|
107
117
|
throw err;
|
|
108
118
|
}
|
|
119
|
+
const normalizedGenConfig = normalizeGenerationConfig(generationConfig);
|
|
120
|
+
const requestBody = {
|
|
121
|
+
model: activeModel,
|
|
122
|
+
contents,
|
|
123
|
+
tools,
|
|
124
|
+
toolConfig,
|
|
125
|
+
systemInstruction,
|
|
126
|
+
};
|
|
127
|
+
if (normalizedGenConfig && Object.keys(normalizedGenConfig).length > 0) {
|
|
128
|
+
requestBody.generationConfig = normalizedGenConfig;
|
|
129
|
+
}
|
|
109
130
|
const response = await fetch(this.PROXY_URL, {
|
|
110
131
|
method: 'POST',
|
|
111
132
|
headers: {
|
|
112
133
|
'Content-Type': 'application/json',
|
|
113
134
|
'X-Firebase-Auth': `Bearer ${idToken}`,
|
|
114
135
|
},
|
|
115
|
-
body: JSON.stringify(
|
|
116
|
-
model: activeModel,
|
|
117
|
-
contents,
|
|
118
|
-
tools,
|
|
119
|
-
toolConfig,
|
|
120
|
-
systemInstruction,
|
|
121
|
-
generationConfig,
|
|
122
|
-
}),
|
|
136
|
+
body: JSON.stringify(requestBody),
|
|
123
137
|
signal: abortSignal,
|
|
124
138
|
});
|
|
125
|
-
|
|
139
|
+
const thinkingLevel = generationConfig?.thinkingConfig?.thinkingLevel || 'DEFAULT';
|
|
140
|
+
debugLog(`Proxy Request to ${activeModel} (thinking: ${thinkingLevel}) complete. Status: ${response.status} ${response.statusText}`);
|
|
126
141
|
if (response.status === 429 || response.status === 503 || response.status === 502 || response.status === 500 || response.status === 504) {
|
|
127
142
|
if (attempt < MAX_RETRIES) {
|
|
128
143
|
if (abortSignal?.aborted) {
|
|
@@ -342,6 +357,7 @@ export class ProxyClient {
|
|
|
342
357
|
async generateViaBYOK(apiKey, modelName, contents, tools, toolConfig, systemInstruction, generationConfig, streamCallbacks, abortSignal) {
|
|
343
358
|
const isStreaming = Boolean(streamCallbacks?.onChunk);
|
|
344
359
|
const formattedSystemInstruction = typeof systemInstruction === 'string' ? { parts: [{ text: systemInstruction }] } : systemInstruction;
|
|
360
|
+
const normalizedGenConfig = normalizeGenerationConfig(generationConfig);
|
|
345
361
|
const payload = { contents };
|
|
346
362
|
if (tools && tools.length > 0)
|
|
347
363
|
payload.tools = tools;
|
|
@@ -349,8 +365,9 @@ export class ProxyClient {
|
|
|
349
365
|
payload.toolConfig = toolConfig;
|
|
350
366
|
if (formattedSystemInstruction)
|
|
351
367
|
payload.systemInstruction = formattedSystemInstruction;
|
|
352
|
-
if (
|
|
353
|
-
payload.generationConfig =
|
|
368
|
+
if (normalizedGenConfig && Object.keys(normalizedGenConfig).length > 0) {
|
|
369
|
+
payload.generationConfig = normalizedGenConfig;
|
|
370
|
+
}
|
|
354
371
|
const MAX_RETRIES = 5;
|
|
355
372
|
const BASE_DELAY_MS = 2000;
|
|
356
373
|
const MAX_DELAY_MS = 30000;
|
|
@@ -370,7 +387,8 @@ export class ProxyClient {
|
|
|
370
387
|
body: JSON.stringify(payload),
|
|
371
388
|
signal: abortSignal,
|
|
372
389
|
});
|
|
373
|
-
|
|
390
|
+
const thinkingLevel = generationConfig?.thinkingConfig?.thinkingLevel || 'DEFAULT';
|
|
391
|
+
debugLog(`BYOK Request to ${activeModel} (thinking: ${thinkingLevel}) complete. Status: ${response.status} ${response.statusText}`);
|
|
374
392
|
if (response.status === 429 ||
|
|
375
393
|
response.status === 503 ||
|
|
376
394
|
response.status === 502 ||
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -23,6 +23,21 @@ export declare const GEMINI_MODELS: {
|
|
|
23
23
|
readonly FLASH_LITE: "gemini-3.5-flash-lite";
|
|
24
24
|
readonly AUTO: "auto";
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Supported native thinking reasoning levels for Gemini 3.x series models.
|
|
28
|
+
*/
|
|
29
|
+
export type ThinkingLevel = 'MINIMAL' | 'LOW' | 'MEDIUM' | 'HIGH';
|
|
30
|
+
/**
|
|
31
|
+
* Thinking configuration structure for Gemini API generation requests.
|
|
32
|
+
*/
|
|
33
|
+
export interface ThinkingConfig {
|
|
34
|
+
thinkingLevel?: ThinkingLevel;
|
|
35
|
+
includeThoughts?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Default thinking level mappings per model for reasoning budget allocation.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_MODEL_THINKING_LEVELS: Record<string, ThinkingLevel>;
|
|
26
41
|
/** Default Gemini model for the coding agent. */
|
|
27
42
|
export declare const DEFAULT_MODEL: "auto";
|
|
28
43
|
/** Maximum tokens the model can output per response. */
|
|
@@ -49,7 +64,67 @@ export declare const TPM_COOLING_DELAYS: {
|
|
|
49
64
|
readonly ORCHESTRATION_RECONCILE_MS: 2000;
|
|
50
65
|
/** Pause before sending automated verification self-correction prompts */
|
|
51
66
|
readonly CORRECTION_TURN_MS: 2000;
|
|
67
|
+
/** Stagger delay when spawning concurrent sub-agents to avoid rate burst */
|
|
68
|
+
readonly SUB_AGENT_SPAWN_MS: 1500;
|
|
69
|
+
/** Subtle inter-tool execution delay for burst protection during high-frequency loops */
|
|
70
|
+
readonly TOOL_CALL_PACING_MS: 1000;
|
|
71
|
+
/** Deliberate settling recovery window after massive token generations */
|
|
72
|
+
readonly BURST_RECOVERY_MS: 4000;
|
|
73
|
+
/** Token threshold above which heavy-prompt adaptive cooling delays are applied */
|
|
74
|
+
readonly HEAVY_PROMPT_THRESHOLD_TOKENS: 100000;
|
|
75
|
+
/** Minimum adaptive cooling delay bound in milliseconds */
|
|
76
|
+
readonly ADAPTIVE_PACING_MIN_MS: 1000;
|
|
77
|
+
/** Maximum adaptive cooling delay bound in milliseconds */
|
|
78
|
+
readonly ADAPTIVE_PACING_MAX_MS: 8000;
|
|
52
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* Standardized rate limiting and exponential backoff configuration.
|
|
82
|
+
*/
|
|
83
|
+
export declare const RATE_LIMIT_CONFIG: {
|
|
84
|
+
/** Maximum retry attempts for transient 429 / 503 / 500 server errors */
|
|
85
|
+
readonly MAX_RETRIES: 5;
|
|
86
|
+
/** Base backoff delay in milliseconds */
|
|
87
|
+
readonly BASE_DELAY_MS: 2000;
|
|
88
|
+
/** Maximum backoff delay cap in milliseconds */
|
|
89
|
+
readonly MAX_DELAY_MS: 30000;
|
|
90
|
+
/** Multiplicative exponential backoff factor */
|
|
91
|
+
readonly BACKOFF_FACTOR: 2.5;
|
|
92
|
+
/** Random jitter factor applied to backoff delays to prevent thundering herd */
|
|
93
|
+
readonly JITTER_FACTOR: 0.5;
|
|
94
|
+
/** Default target tokens-per-minute threshold across rolling 60-second window */
|
|
95
|
+
readonly DEFAULT_TPM_LIMIT: 4000000;
|
|
96
|
+
/** Safety buffer threshold before triggering adaptive TPM pacing (85% capacity) */
|
|
97
|
+
readonly TARGET_TOKEN_PACING_BUFFER: 0.85;
|
|
98
|
+
/** Maximum concurrent sub-agents allowed to prevent rate limit exhaustion */
|
|
99
|
+
readonly MAX_PARALLEL_SUBAGENTS: 3;
|
|
100
|
+
/** Estimated tokens per character heuristic (approx. 4 characters per token) */
|
|
101
|
+
readonly ESTIMATED_TOKENS_PER_CHAR: 0.25;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Estimates token count from character length using standard tokenization heuristics.
|
|
105
|
+
*
|
|
106
|
+
* @param charCount Number of characters in the string.
|
|
107
|
+
* @returns Estimated number of tokens.
|
|
108
|
+
*/
|
|
109
|
+
export declare function estimateTokensFromCharLength(charCount: number): number;
|
|
110
|
+
/**
|
|
111
|
+
* Calculates dynamic adaptive pacing delay (in milliseconds) based on prompt token volume
|
|
112
|
+
* and provider tier (BYOK vs Proxy).
|
|
113
|
+
*
|
|
114
|
+
* @param estimatedInputTokens Estimated prompt tokens for the upcoming call.
|
|
115
|
+
* @param isByok Whether the user is using Bring-Your-Own-Key.
|
|
116
|
+
* @returns Delay duration in milliseconds.
|
|
117
|
+
*/
|
|
118
|
+
export declare function calculateAdaptivePacingDelay(estimatedInputTokens?: number, isByok?: boolean): number;
|
|
119
|
+
/**
|
|
120
|
+
* Returns the recommended cooling-off delay for a specific operational phase,
|
|
121
|
+
* optionally factoring in token volume.
|
|
122
|
+
*
|
|
123
|
+
* @param phase Operational phase key.
|
|
124
|
+
* @param tokenCount Optional estimated token count for dynamic scaling.
|
|
125
|
+
* @returns Delay in milliseconds.
|
|
126
|
+
*/
|
|
127
|
+
export declare function getSmartPacingDelay(phase: keyof typeof TPM_COOLING_DELAYS | string, tokenCount?: number): number;
|
|
53
128
|
/**
|
|
54
129
|
* Checks if BYOK is currently enabled for the user.
|
|
55
130
|
*/
|
package/dist/utils/config.js
CHANGED
|
@@ -23,6 +23,16 @@ export const GEMINI_MODELS = {
|
|
|
23
23
|
FLASH_LITE: 'gemini-3.5-flash-lite',
|
|
24
24
|
AUTO: 'auto',
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Default thinking level mappings per model for reasoning budget allocation.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_MODEL_THINKING_LEVELS = {
|
|
30
|
+
[GEMINI_MODELS.FLASH_3_7]: 'MEDIUM',
|
|
31
|
+
[GEMINI_MODELS.FLASH_3_6]: 'MEDIUM',
|
|
32
|
+
[GEMINI_MODELS.PRO]: 'HIGH',
|
|
33
|
+
[GEMINI_MODELS.FLASH_LITE]: 'LOW',
|
|
34
|
+
[GEMINI_MODELS.AUTO]: 'MEDIUM',
|
|
35
|
+
};
|
|
26
36
|
/** Default Gemini model for the coding agent. */
|
|
27
37
|
export const DEFAULT_MODEL = GEMINI_MODELS.AUTO;
|
|
28
38
|
/** Maximum tokens the model can output per response. */
|
|
@@ -49,7 +59,90 @@ export const TPM_COOLING_DELAYS = {
|
|
|
49
59
|
ORCHESTRATION_RECONCILE_MS: 2000,
|
|
50
60
|
/** Pause before sending automated verification self-correction prompts */
|
|
51
61
|
CORRECTION_TURN_MS: 2000,
|
|
62
|
+
/** Stagger delay when spawning concurrent sub-agents to avoid rate burst */
|
|
63
|
+
SUB_AGENT_SPAWN_MS: 1500,
|
|
64
|
+
/** Subtle inter-tool execution delay for burst protection during high-frequency loops */
|
|
65
|
+
TOOL_CALL_PACING_MS: 1000,
|
|
66
|
+
/** Deliberate settling recovery window after massive token generations */
|
|
67
|
+
BURST_RECOVERY_MS: 4000,
|
|
68
|
+
/** Token threshold above which heavy-prompt adaptive cooling delays are applied */
|
|
69
|
+
HEAVY_PROMPT_THRESHOLD_TOKENS: 100_000,
|
|
70
|
+
/** Minimum adaptive cooling delay bound in milliseconds */
|
|
71
|
+
ADAPTIVE_PACING_MIN_MS: 1000,
|
|
72
|
+
/** Maximum adaptive cooling delay bound in milliseconds */
|
|
73
|
+
ADAPTIVE_PACING_MAX_MS: 8000,
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Standardized rate limiting and exponential backoff configuration.
|
|
77
|
+
*/
|
|
78
|
+
export const RATE_LIMIT_CONFIG = {
|
|
79
|
+
/** Maximum retry attempts for transient 429 / 503 / 500 server errors */
|
|
80
|
+
MAX_RETRIES: 5,
|
|
81
|
+
/** Base backoff delay in milliseconds */
|
|
82
|
+
BASE_DELAY_MS: 2000,
|
|
83
|
+
/** Maximum backoff delay cap in milliseconds */
|
|
84
|
+
MAX_DELAY_MS: 30_000,
|
|
85
|
+
/** Multiplicative exponential backoff factor */
|
|
86
|
+
BACKOFF_FACTOR: 2.5,
|
|
87
|
+
/** Random jitter factor applied to backoff delays to prevent thundering herd */
|
|
88
|
+
JITTER_FACTOR: 0.5,
|
|
89
|
+
/** Default target tokens-per-minute threshold across rolling 60-second window */
|
|
90
|
+
DEFAULT_TPM_LIMIT: 4_000_000,
|
|
91
|
+
/** Safety buffer threshold before triggering adaptive TPM pacing (85% capacity) */
|
|
92
|
+
TARGET_TOKEN_PACING_BUFFER: 0.85,
|
|
93
|
+
/** Maximum concurrent sub-agents allowed to prevent rate limit exhaustion */
|
|
94
|
+
MAX_PARALLEL_SUBAGENTS: 3,
|
|
95
|
+
/** Estimated tokens per character heuristic (approx. 4 characters per token) */
|
|
96
|
+
ESTIMATED_TOKENS_PER_CHAR: 0.25,
|
|
52
97
|
};
|
|
98
|
+
/**
|
|
99
|
+
* Estimates token count from character length using standard tokenization heuristics.
|
|
100
|
+
*
|
|
101
|
+
* @param charCount Number of characters in the string.
|
|
102
|
+
* @returns Estimated number of tokens.
|
|
103
|
+
*/
|
|
104
|
+
export function estimateTokensFromCharLength(charCount) {
|
|
105
|
+
return Math.ceil(charCount * RATE_LIMIT_CONFIG.ESTIMATED_TOKENS_PER_CHAR);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Calculates dynamic adaptive pacing delay (in milliseconds) based on prompt token volume
|
|
109
|
+
* and provider tier (BYOK vs Proxy).
|
|
110
|
+
*
|
|
111
|
+
* @param estimatedInputTokens Estimated prompt tokens for the upcoming call.
|
|
112
|
+
* @param isByok Whether the user is using Bring-Your-Own-Key.
|
|
113
|
+
* @returns Delay duration in milliseconds.
|
|
114
|
+
*/
|
|
115
|
+
export function calculateAdaptivePacingDelay(estimatedInputTokens = 0, isByok = false) {
|
|
116
|
+
if (estimatedInputTokens <= 0) {
|
|
117
|
+
return isByok ? TPM_COOLING_DELAYS.ADAPTIVE_PACING_MIN_MS / 2 : TPM_COOLING_DELAYS.ADAPTIVE_PACING_MIN_MS;
|
|
118
|
+
}
|
|
119
|
+
const threshold = TPM_COOLING_DELAYS.HEAVY_PROMPT_THRESHOLD_TOKENS;
|
|
120
|
+
if (estimatedInputTokens < threshold) {
|
|
121
|
+
return TPM_COOLING_DELAYS.ADAPTIVE_PACING_MIN_MS;
|
|
122
|
+
}
|
|
123
|
+
// Scale linearly between MIN and MAX based on token weight exceeding threshold
|
|
124
|
+
const ratio = Math.min(1.0, (estimatedInputTokens - threshold) / threshold);
|
|
125
|
+
const dynamicDelay = TPM_COOLING_DELAYS.ADAPTIVE_PACING_MIN_MS +
|
|
126
|
+
ratio * (TPM_COOLING_DELAYS.ADAPTIVE_PACING_MAX_MS - TPM_COOLING_DELAYS.ADAPTIVE_PACING_MIN_MS);
|
|
127
|
+
// BYOK users may have higher or lower custom tier limits, apply modest discount
|
|
128
|
+
return Math.round(isByok ? dynamicDelay * 0.8 : dynamicDelay);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Returns the recommended cooling-off delay for a specific operational phase,
|
|
132
|
+
* optionally factoring in token volume.
|
|
133
|
+
*
|
|
134
|
+
* @param phase Operational phase key.
|
|
135
|
+
* @param tokenCount Optional estimated token count for dynamic scaling.
|
|
136
|
+
* @returns Delay in milliseconds.
|
|
137
|
+
*/
|
|
138
|
+
export function getSmartPacingDelay(phase, tokenCount) {
|
|
139
|
+
const baseDelay = TPM_COOLING_DELAYS[phase] ?? TPM_COOLING_DELAYS.INTER_TURN_MS;
|
|
140
|
+
if (typeof tokenCount === 'number' && tokenCount > TPM_COOLING_DELAYS.HEAVY_PROMPT_THRESHOLD_TOKENS) {
|
|
141
|
+
const adaptive = calculateAdaptivePacingDelay(tokenCount);
|
|
142
|
+
return Math.max(baseDelay, adaptive);
|
|
143
|
+
}
|
|
144
|
+
return baseDelay;
|
|
145
|
+
}
|
|
53
146
|
/**
|
|
54
147
|
* Checks if BYOK is currently enabled for the user.
|
|
55
148
|
*/
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
+
import { ContextAgentResult } from '../services/contextAgent.js';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
* injection strings to be sent to the AI model. Includes handling of CDATA block
|
|
4
|
-
* formatting, character/token budgeting, and lightweight AST-scoped context extraction.
|
|
3
|
+
* Standard character and token budgeting constants for context injections.
|
|
5
4
|
*/
|
|
6
|
-
|
|
5
|
+
export declare const CONTEXT_BUDGET_CONFIG: {
|
|
6
|
+
/** Default maximum character budget for full context injections (~60,000 tokens) */
|
|
7
|
+
readonly DEFAULT_CONTEXT_MAX_CHARS: 240000;
|
|
8
|
+
/** Default maximum character budget for scoped context injections (~30,000 tokens) */
|
|
9
|
+
readonly DEFAULT_SCOPED_MAX_CHARS: 120000;
|
|
10
|
+
/** Estimated characters per token heuristic */
|
|
11
|
+
readonly ESTIMATED_CHARS_PER_TOKEN: 4;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Estimates token count from a given text string.
|
|
15
|
+
*
|
|
16
|
+
* @param text The input text to measure.
|
|
17
|
+
* @returns Estimated number of tokens.
|
|
18
|
+
*/
|
|
19
|
+
export declare function estimateTokens(text: string): number;
|
|
7
20
|
/**
|
|
8
21
|
* Sanitizes file content string to prevent nesting or breakout issues when wrapped in CDATA.
|
|
9
22
|
* Replaces occurrences of "]]\u200B>" with an escaped equivalent containing a zero-width space.
|
|
@@ -37,3 +50,14 @@ export declare function buildContextInjection(context: ContextAgentResult, maxCh
|
|
|
37
50
|
* @returns A formatted string containing project profile, structure, investigation summaries, and AST-scoped file outlines.
|
|
38
51
|
*/
|
|
39
52
|
export declare function buildScopedContextInjection(context: ContextAgentResult, maxChars?: number): string;
|
|
53
|
+
/**
|
|
54
|
+
* Formats an array of resolved context mention blocks into a single structured
|
|
55
|
+
* XML `<context_mentions>` block adhering to character/token budget constraints.
|
|
56
|
+
*
|
|
57
|
+
* @param resolvedBlocks Array of objects with content string.
|
|
58
|
+
* @param maxChars Optional maximum character budget.
|
|
59
|
+
* @returns Unified XML context block.
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatContextMentions(resolvedBlocks: Array<{
|
|
62
|
+
content: string;
|
|
63
|
+
}>, maxChars?: number): string;
|
|
@@ -5,6 +5,28 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { changeLogger } from '../services/changeLogger.js';
|
|
7
7
|
import { extractDeclarationsOutline } from './symbolExtractor.js';
|
|
8
|
+
/**
|
|
9
|
+
* Standard character and token budgeting constants for context injections.
|
|
10
|
+
*/
|
|
11
|
+
export const CONTEXT_BUDGET_CONFIG = {
|
|
12
|
+
/** Default maximum character budget for full context injections (~60,000 tokens) */
|
|
13
|
+
DEFAULT_CONTEXT_MAX_CHARS: 240_000,
|
|
14
|
+
/** Default maximum character budget for scoped context injections (~30,000 tokens) */
|
|
15
|
+
DEFAULT_SCOPED_MAX_CHARS: 120_000,
|
|
16
|
+
/** Estimated characters per token heuristic */
|
|
17
|
+
ESTIMATED_CHARS_PER_TOKEN: 4,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Estimates token count from a given text string.
|
|
21
|
+
*
|
|
22
|
+
* @param text The input text to measure.
|
|
23
|
+
* @returns Estimated number of tokens.
|
|
24
|
+
*/
|
|
25
|
+
export function estimateTokens(text) {
|
|
26
|
+
if (!text)
|
|
27
|
+
return 0;
|
|
28
|
+
return Math.ceil(text.length / CONTEXT_BUDGET_CONFIG.ESTIMATED_CHARS_PER_TOKEN);
|
|
29
|
+
}
|
|
8
30
|
/**
|
|
9
31
|
* Sanitizes file content string to prevent nesting or breakout issues when wrapped in CDATA.
|
|
10
32
|
* Replaces occurrences of "]]\u200B>" with an escaped equivalent containing a zero-width space.
|
|
@@ -13,7 +35,7 @@ import { extractDeclarationsOutline } from './symbolExtractor.js';
|
|
|
13
35
|
* @returns The sanitized string safe to place inside a CDATA section.
|
|
14
36
|
*/
|
|
15
37
|
export function sanitizeForCDATA(content) {
|
|
16
|
-
// Prevent CDATA breakout by escaping ]]>
|
|
38
|
+
// Prevent CDATA breakout by escaping ]]\\u200B>
|
|
17
39
|
return content.replace(new RegExp('\\]\\]>', 'g'), ']]\\\\u200B>');
|
|
18
40
|
}
|
|
19
41
|
/**
|
|
@@ -136,6 +158,17 @@ function assembleContextWithFiles(baseContext, relevantFiles, maxChars, useScope
|
|
|
136
158
|
injection += fullBlock;
|
|
137
159
|
continue;
|
|
138
160
|
}
|
|
161
|
+
// Token-efficiency optimization: If full file does not fit and wasn't scoped, attempt AST outline first
|
|
162
|
+
if (!useScopedOutline) {
|
|
163
|
+
const outlinedText = extractDeclarationsOutline(contentText, filePath);
|
|
164
|
+
if (outlinedText) {
|
|
165
|
+
const outlinedBlock = formatWorkspaceFileBlock(filePath, outlinedText, true);
|
|
166
|
+
if (outlinedBlock.length <= remainingBudgetForThisFile) {
|
|
167
|
+
injection += outlinedBlock;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
139
172
|
// Try partial/truncated block
|
|
140
173
|
const emptyBlock = formatWorkspaceFileBlock(filePath, '', useScopedOutline);
|
|
141
174
|
const wrapperOverhead = emptyBlock.length;
|
|
@@ -194,3 +227,39 @@ export function buildScopedContextInjection(context, maxChars) {
|
|
|
194
227
|
const baseContext = buildBaseContext(context);
|
|
195
228
|
return assembleContextWithFiles(baseContext, context.relevantFiles, maxChars, true);
|
|
196
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Formats an array of resolved context mention blocks into a single structured
|
|
232
|
+
* XML `<context_mentions>` block adhering to character/token budget constraints.
|
|
233
|
+
*
|
|
234
|
+
* @param resolvedBlocks Array of objects with content string.
|
|
235
|
+
* @param maxChars Optional maximum character budget.
|
|
236
|
+
* @returns Unified XML context block.
|
|
237
|
+
*/
|
|
238
|
+
export function formatContextMentions(resolvedBlocks, maxChars = CONTEXT_BUDGET_CONFIG.DEFAULT_CONTEXT_MAX_CHARS) {
|
|
239
|
+
if (!resolvedBlocks || resolvedBlocks.length === 0)
|
|
240
|
+
return '';
|
|
241
|
+
const validBlocks = resolvedBlocks.filter((b) => b.content && b.content.trim());
|
|
242
|
+
if (validBlocks.length === 0)
|
|
243
|
+
return '';
|
|
244
|
+
let combined = '<context_mentions>\n';
|
|
245
|
+
const closingTag = '\n</context_mentions>';
|
|
246
|
+
for (let i = 0; i < validBlocks.length; i++) {
|
|
247
|
+
const block = validBlocks[i];
|
|
248
|
+
const nextContent = `${block.content}\n`;
|
|
249
|
+
if (maxChars && combined.length + nextContent.length + closingTag.length > maxChars) {
|
|
250
|
+
const remaining = validBlocks.length - i;
|
|
251
|
+
const omissionNotice = `<!-- ${remaining} mention context block(s) omitted to stay within token budget -->\n`;
|
|
252
|
+
if (combined.length + omissionNotice.length + closingTag.length <= maxChars) {
|
|
253
|
+
combined += omissionNotice;
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
combined += nextContent;
|
|
258
|
+
}
|
|
259
|
+
combined += '</context_mentions>';
|
|
260
|
+
if (maxChars && combined.length > maxChars) {
|
|
261
|
+
const keepChars = Math.max(0, maxChars - closingTag.length);
|
|
262
|
+
combined = `${combined.slice(0, keepChars).trimEnd()}${closingTag}`;
|
|
263
|
+
}
|
|
264
|
+
return combined;
|
|
265
|
+
}
|
|
@@ -1,3 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents an individual autocomplete suggestion item for @ context mentions.
|
|
3
|
+
*/
|
|
4
|
+
export interface AutocompleteItem {
|
|
5
|
+
/** Optional unique identifier for the suggestion */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** The value or token to insert into the input buffer (e.g. "@src/utils/historyPrompt.ts" or "@git:diff") */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Display label shown in the dropdown list */
|
|
10
|
+
label: string;
|
|
11
|
+
/** Category badge type (e.g. 'file', 'lines', 'symbol', 'sym', 'git', 'workspace', 'ws', 'diagnostics', 'diag', 'problem', 'prob', 'terminal', 'term', 'doc') */
|
|
12
|
+
category?: 'file' | 'lines' | 'line' | 'symbol' | 'sym' | 'git' | 'workspace' | 'ws' | 'diagnostics' | 'diag' | 'problem' | 'prob' | 'terminal' | 'term' | 'doc' | string;
|
|
13
|
+
/** Short secondary description or path info */
|
|
14
|
+
description?: string;
|
|
15
|
+
/** Additional metadata for advanced resolvers */
|
|
16
|
+
metadata?: Record<string, any>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Configuration options governing real-time @ autocomplete behavior.
|
|
20
|
+
*/
|
|
21
|
+
export interface AutocompleteOptions {
|
|
22
|
+
/** Whether autocomplete is enabled. Defaults to true. */
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
/** Maximum number of suggestions displayed in the popup list at once. Defaults to 10. */
|
|
25
|
+
maxVisibleItems?: number;
|
|
26
|
+
/** Custom suggestion provider returning static or dynamic suggestions. */
|
|
27
|
+
getSuggestions?: (query: string, context: {
|
|
28
|
+
fullText: string;
|
|
29
|
+
cursor: number;
|
|
30
|
+
}) => AutocompleteItem[] | Promise<AutocompleteItem[]>;
|
|
31
|
+
/** Custom filter/ranking function for suggestions */
|
|
32
|
+
filter?: (items: AutocompleteItem[], query: string) => AutocompleteItem[];
|
|
33
|
+
/** Alias for filter */
|
|
34
|
+
filterSuggestions?: (items: AutocompleteItem[], query: string) => AutocompleteItem[];
|
|
35
|
+
/** Trigger character(s) that activate autocomplete. Defaults to ['@']. */
|
|
36
|
+
triggers?: string[];
|
|
37
|
+
/** Root directory for workspace file scanning. Defaults to process.cwd(). */
|
|
38
|
+
workspaceRoot?: string;
|
|
39
|
+
/** Whether pressing Tab completes the selected suggestion. Defaults to true. */
|
|
40
|
+
tabCompletion?: boolean;
|
|
41
|
+
/** Whether pressing Enter when autocomplete is open completes the suggestion (false submits prompt). Defaults to false. */
|
|
42
|
+
enterCompletion?: boolean;
|
|
43
|
+
/** Cache timeout in ms for file and workspace scanning. Defaults to 5000ms. */
|
|
44
|
+
cacheTtlMs?: number;
|
|
45
|
+
}
|
|
1
46
|
/**
|
|
2
47
|
* Configuration options for the history-enabled text prompt.
|
|
3
48
|
*/
|
|
@@ -16,6 +61,17 @@ export interface HistoryTextOptions {
|
|
|
16
61
|
maxHistoryLength?: number;
|
|
17
62
|
/** Callback to validate the user input. */
|
|
18
63
|
validate?: (value: string) => string | Error | undefined;
|
|
64
|
+
/** Autocomplete configuration options for @ context mentions and symbols. */
|
|
65
|
+
autocomplete?: boolean | AutocompleteOptions;
|
|
66
|
+
/** Optional custom suggestion provider shortcut */
|
|
67
|
+
getSuggestions?: (query: string, context: {
|
|
68
|
+
fullText: string;
|
|
69
|
+
cursor: number;
|
|
70
|
+
}) => AutocompleteItem[] | Promise<AutocompleteItem[]>;
|
|
71
|
+
/** Optional custom readable input stream (e.g. for testing) */
|
|
72
|
+
input?: NodeJS.ReadableStream;
|
|
73
|
+
/** Optional custom writable output stream (e.g. for testing) */
|
|
74
|
+
output?: NodeJS.WritableStream;
|
|
19
75
|
}
|
|
20
76
|
/**
|
|
21
77
|
* Configuration options for dynamic token budget calculation.
|
|
@@ -67,13 +123,15 @@ export declare function calculateDynamicTokenBudget(config: TokenBudgetConfig):
|
|
|
67
123
|
* @param text The text to prune.
|
|
68
124
|
* @param maxTokens Maximum allowable tokens for this text.
|
|
69
125
|
* @param options Pruning options.
|
|
126
|
+
* @param options.truncationMarker Marker to append/prepend indicating truncation.
|
|
127
|
+
* @param options.fromStart If true, prunes from the start.
|
|
70
128
|
* @returns Pruned string, with an optional truncation marker.
|
|
71
129
|
*/
|
|
72
130
|
export declare function pruneTextToTokenBudget(text: string, maxTokens: number, options?: {
|
|
73
|
-
/** Marker to append/prepend indicating truncation. */
|
|
74
|
-
truncationMarker?: string;
|
|
75
131
|
/** If true, prunes from the start (keeping the end). If false, prunes from the end (keeping the start). */
|
|
76
132
|
fromStart?: boolean;
|
|
133
|
+
/** Marker to append/prepend indicating truncation. */
|
|
134
|
+
truncationMarker?: string;
|
|
77
135
|
}): string;
|
|
78
136
|
/**
|
|
79
137
|
* Optimizes an array of history strings by trimming whitespace, deduplicating consecutive items,
|
|
@@ -89,25 +147,126 @@ export declare function optimizeHistoryForContext(history: string[] | undefined,
|
|
|
89
147
|
* pruning older turns if the total estimated tokens exceed the allocated budget.
|
|
90
148
|
*
|
|
91
149
|
* @param history Array of conversation turns with role and text content.
|
|
92
|
-
* @param maxTokens Maximum allowable tokens for the formatted history.
|
|
150
|
+
* @param maxTokens Maximum allowable tokens for the formatted history. Defaults to 16_384.
|
|
93
151
|
* @param options Formatting options.
|
|
152
|
+
* @param options.keepRecentTurns Minimum number of recent turns to always keep regardless of budget if possible. Defaults to 2.
|
|
153
|
+
* @param options.userLabel Custom label prefix for user turns. Defaults to "User".
|
|
154
|
+
* @param options.modelLabel Custom label prefix for assistant/model turns. Defaults to "Assistant".
|
|
94
155
|
* @returns Formatted and budget-constrained conversation history string.
|
|
95
156
|
*/
|
|
96
157
|
export declare function formatHistoryWithTokenBudget(history: Array<{
|
|
158
|
+
parts?: any[];
|
|
97
159
|
role: string;
|
|
98
160
|
text?: string;
|
|
99
|
-
parts?: any[];
|
|
100
161
|
}>, maxTokens?: number, options?: {
|
|
101
162
|
/** Minimum number of recent turns to always keep regardless of budget if possible. Defaults to 2. */
|
|
102
163
|
keepRecentTurns?: number;
|
|
103
|
-
/** Custom label prefix for user turns. Defaults to "User". */
|
|
104
|
-
userLabel?: string;
|
|
105
164
|
/** Custom label prefix for assistant/model turns. Defaults to "Assistant". */
|
|
106
165
|
modelLabel?: string;
|
|
166
|
+
/** Custom label prefix for user turns. Defaults to "User". */
|
|
167
|
+
userLabel?: string;
|
|
107
168
|
}): string;
|
|
169
|
+
/**
|
|
170
|
+
* Extracts an active mention trigger token (such as `@query`) directly preceding the cursor.
|
|
171
|
+
*
|
|
172
|
+
* @param line - The full input line buffer.
|
|
173
|
+
* @param cursor - The current cursor index within the line buffer.
|
|
174
|
+
* @param triggers - Allowed trigger prefix characters (defaults to `['@']`).
|
|
175
|
+
* @returns An object containing query string and starting trigger index, or `null` if not active.
|
|
176
|
+
*/
|
|
177
|
+
export declare function extractMentionQuery(line: string, cursor: number, triggers?: string[]): {
|
|
178
|
+
query: string;
|
|
179
|
+
triggerIndex: number;
|
|
180
|
+
trigger: string;
|
|
181
|
+
} | null;
|
|
182
|
+
/**
|
|
183
|
+
* Scores an autocomplete item against a search query for fuzzy and prefix ranking.
|
|
184
|
+
*
|
|
185
|
+
* @param item - The autocomplete candidate.
|
|
186
|
+
* @param query - The user search query without trigger prefix.
|
|
187
|
+
* @returns Numerical score (higher score = better match, 0 = no match).
|
|
188
|
+
*/
|
|
189
|
+
export declare function scoreAutocompleteItem(item: AutocompleteItem, query: string): number;
|
|
190
|
+
/**
|
|
191
|
+
* Filters and ranks suggestions according to match quality.
|
|
192
|
+
*
|
|
193
|
+
* @param items - Candidate autocomplete suggestions.
|
|
194
|
+
* @param query - The search query string.
|
|
195
|
+
* @param maxItems - Maximum number of top items to return.
|
|
196
|
+
* @returns Ranked subset of suggestions.
|
|
197
|
+
*/
|
|
198
|
+
export declare function filterAndRankSuggestions(items: AutocompleteItem[], query: string, maxItems?: number): AutocompleteItem[];
|
|
199
|
+
/**
|
|
200
|
+
* Formats a terminal-styled category badge with picocolors.
|
|
201
|
+
*
|
|
202
|
+
* @param category - Category name (e.g. 'lines', 'sym', 'git', 'diag', 'term', 'ws', 'file').
|
|
203
|
+
* @returns Formatted ANSI badge string.
|
|
204
|
+
*/
|
|
205
|
+
export declare function formatCategoryBadge(category?: string): string;
|
|
206
|
+
/**
|
|
207
|
+
* Renders an aesthetically styled autocomplete popup dropdown box for terminal display.
|
|
208
|
+
*
|
|
209
|
+
* @param suggestions - Current list of visible suggestions.
|
|
210
|
+
* @param selectedIndex - Currently selected item index.
|
|
211
|
+
* @param maxVisible - Maximum number of items visible simultaneously.
|
|
212
|
+
* @returns Multi-line ANSI string representing the autocomplete popup.
|
|
213
|
+
*/
|
|
214
|
+
export declare function renderAutocompletePopup(suggestions: AutocompleteItem[], selectedIndex: number, maxVisible?: number): string;
|
|
215
|
+
/**
|
|
216
|
+
* Resolver for dynamic workspace files, git actions, and registered external workspaces.
|
|
217
|
+
*/
|
|
218
|
+
export declare class ContextMentionResolver {
|
|
219
|
+
private cachedFiles;
|
|
220
|
+
private externalWorkspaceCache;
|
|
221
|
+
private symbolCache;
|
|
222
|
+
private cacheTimestamp;
|
|
223
|
+
private cacheTtlMs;
|
|
224
|
+
private workspaceRoot;
|
|
225
|
+
constructor(workspaceRoot?: string, cacheTtlMs?: number);
|
|
226
|
+
/**
|
|
227
|
+
* Clears in-memory file scanning caches.
|
|
228
|
+
*/
|
|
229
|
+
clearCache(): void;
|
|
230
|
+
/**
|
|
231
|
+
* Returns standard built-in git, diagnostic, terminal, and symbol context mention options.
|
|
232
|
+
*/
|
|
233
|
+
getBuiltInMentions(): AutocompleteItem[];
|
|
234
|
+
/**
|
|
235
|
+
* Scans and caches workspace relative file paths up to depth limit.
|
|
236
|
+
*
|
|
237
|
+
* @param targetRoot - Directory root to scan. Defaults to this.workspaceRoot.
|
|
238
|
+
* @returns Array of relative file paths within the target root.
|
|
239
|
+
*/
|
|
240
|
+
getWorkspaceFiles(targetRoot?: string): string[];
|
|
241
|
+
/**
|
|
242
|
+
* Returns registered external workspaces as autocomplete items.
|
|
243
|
+
*/
|
|
244
|
+
getWorkspaceMentions(): AutocompleteItem[];
|
|
245
|
+
/**
|
|
246
|
+
* Collects base mention items including builtins, registered workspace descriptors,
|
|
247
|
+
* local files, and external workspace files if matching an external workspace alias query.
|
|
248
|
+
*/
|
|
249
|
+
private collectMentionItems;
|
|
250
|
+
/**
|
|
251
|
+
* Resolves, filters, and ranks suggestions matching the user's @ query.
|
|
252
|
+
*/
|
|
253
|
+
resolveSuggestions(query: string, options?: AutocompleteOptions): Promise<AutocompleteItem[]>;
|
|
254
|
+
/**
|
|
255
|
+
* Resolves, filters, and ranks suggestions synchronously for real-time prompt keystrokes.
|
|
256
|
+
*/
|
|
257
|
+
resolveSuggestionsSync(query: string, options?: AutocompleteOptions): AutocompleteItem[];
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Resolves context mentions for an @ query string.
|
|
261
|
+
*
|
|
262
|
+
* @param query - The search query string without the @ prefix.
|
|
263
|
+
* @param options - Optional autocomplete configuration.
|
|
264
|
+
* @returns A promise resolving to ranked autocomplete suggestions.
|
|
265
|
+
*/
|
|
266
|
+
export declare function resolveContextMentions(query: string, options?: AutocompleteOptions): Promise<AutocompleteItem[]>;
|
|
108
267
|
/**
|
|
109
268
|
* A custom text prompt that supports command history navigation using Up/Down arrow keys
|
|
110
|
-
* with memory bounds
|
|
269
|
+
* with memory bounds, dynamic input optimization, and real-time interactive @ autocomplete popups.
|
|
111
270
|
*
|
|
112
271
|
* @param opts - The configuration options for the prompt.
|
|
113
272
|
* @returns A promise that resolves to the user's input string or a symbol if cancelled.
|