@vybestack/llxprt-code-agents 0.10.0-nightly.260613.1adad3b34
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/dist/.last_build +0 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/src/agents/executor-prompt-builder.d.ts +19 -0
- package/dist/src/agents/executor-prompt-builder.js +44 -0
- package/dist/src/agents/executor-prompt-builder.js.map +1 -0
- package/dist/src/agents/executor-termination.d.ts +22 -0
- package/dist/src/agents/executor-termination.js +44 -0
- package/dist/src/agents/executor-termination.js.map +1 -0
- package/dist/src/agents/executor-validation.d.ts +17 -0
- package/dist/src/agents/executor-validation.js +35 -0
- package/dist/src/agents/executor-validation.js.map +1 -0
- package/dist/src/agents/executor.d.ts +136 -0
- package/dist/src/agents/executor.js +874 -0
- package/dist/src/agents/executor.js.map +1 -0
- package/dist/src/agents/invocation.d.ts +45 -0
- package/dist/src/agents/invocation.js +118 -0
- package/dist/src/agents/invocation.js.map +1 -0
- package/dist/src/agents/recovery.d.ts +75 -0
- package/dist/src/agents/recovery.js +107 -0
- package/dist/src/agents/recovery.js.map +1 -0
- package/dist/src/agents/types.d.ts +149 -0
- package/dist/src/agents/types.js +18 -0
- package/dist/src/agents/types.js.map +1 -0
- package/dist/src/agents/utils.d.ts +15 -0
- package/dist/src/agents/utils.js +28 -0
- package/dist/src/agents/utils.js.map +1 -0
- package/dist/src/compression/CompressionHandler.d.ts +178 -0
- package/dist/src/compression/CompressionHandler.js +630 -0
- package/dist/src/compression/CompressionHandler.js.map +1 -0
- package/dist/src/compression/HighDensityStrategy.d.ts +113 -0
- package/dist/src/compression/HighDensityStrategy.js +769 -0
- package/dist/src/compression/HighDensityStrategy.js.map +1 -0
- package/dist/src/compression/MiddleOutStrategy.d.ts +27 -0
- package/dist/src/compression/MiddleOutStrategy.js +347 -0
- package/dist/src/compression/MiddleOutStrategy.js.map +1 -0
- package/dist/src/compression/OneShotStrategy.d.ts +22 -0
- package/dist/src/compression/OneShotStrategy.js +235 -0
- package/dist/src/compression/OneShotStrategy.js.map +1 -0
- package/dist/src/compression/TopDownTruncationStrategy.d.ts +13 -0
- package/dist/src/compression/TopDownTruncationStrategy.js +74 -0
- package/dist/src/compression/TopDownTruncationStrategy.js.map +1 -0
- package/dist/src/compression/compressionBudgeting.d.ts +34 -0
- package/dist/src/compression/compressionBudgeting.js +139 -0
- package/dist/src/compression/compressionBudgeting.js.map +1 -0
- package/dist/src/compression/compressionStrategyFactory.d.ts +23 -0
- package/dist/src/compression/compressionStrategyFactory.js +40 -0
- package/dist/src/compression/compressionStrategyFactory.js.map +1 -0
- package/dist/src/compression/index.d.ts +16 -0
- package/dist/src/compression/index.js +17 -0
- package/dist/src/compression/index.js.map +1 -0
- package/dist/src/compression/reasoningUtils.d.ts +18 -0
- package/dist/src/compression/reasoningUtils.js +22 -0
- package/dist/src/compression/reasoningUtils.js.map +1 -0
- package/dist/src/compression/utils.d.ts +114 -0
- package/dist/src/compression/utils.js +316 -0
- package/dist/src/compression/utils.js.map +1 -0
- package/dist/src/core/AgentHookManager.d.ts +41 -0
- package/dist/src/core/AgentHookManager.js +65 -0
- package/dist/src/core/AgentHookManager.js.map +1 -0
- package/dist/src/core/ChatSessionFactory.d.ts +50 -0
- package/dist/src/core/ChatSessionFactory.js +216 -0
- package/dist/src/core/ChatSessionFactory.js.map +1 -0
- package/dist/src/core/ConversationManager.d.ts +113 -0
- package/dist/src/core/ConversationManager.js +311 -0
- package/dist/src/core/ConversationManager.js.map +1 -0
- package/dist/src/core/DirectMessageProcessor.d.ts +79 -0
- package/dist/src/core/DirectMessageProcessor.js +478 -0
- package/dist/src/core/DirectMessageProcessor.js.map +1 -0
- package/dist/src/core/IdeContextTracker.d.ts +56 -0
- package/dist/src/core/IdeContextTracker.js +207 -0
- package/dist/src/core/IdeContextTracker.js.map +1 -0
- package/dist/src/core/MessageConverter.d.ts +78 -0
- package/dist/src/core/MessageConverter.js +492 -0
- package/dist/src/core/MessageConverter.js.map +1 -0
- package/dist/src/core/MessageStreamOrchestrator.d.ts +85 -0
- package/dist/src/core/MessageStreamOrchestrator.js +448 -0
- package/dist/src/core/MessageStreamOrchestrator.js.map +1 -0
- package/dist/src/core/MessageStreamTerminalHandler.d.ts +16 -0
- package/dist/src/core/MessageStreamTerminalHandler.js +170 -0
- package/dist/src/core/MessageStreamTerminalHandler.js.map +1 -0
- package/dist/src/core/StreamProcessor.d.ts +105 -0
- package/dist/src/core/StreamProcessor.js +660 -0
- package/dist/src/core/StreamProcessor.js.map +1 -0
- package/dist/src/core/TodoContinuationService.d.ts +74 -0
- package/dist/src/core/TodoContinuationService.js +312 -0
- package/dist/src/core/TodoContinuationService.js.map +1 -0
- package/dist/src/core/TurnProcessor.d.ts +91 -0
- package/dist/src/core/TurnProcessor.js +540 -0
- package/dist/src/core/TurnProcessor.js.map +1 -0
- package/dist/src/core/baseLlmClient.d.ts +115 -0
- package/dist/src/core/baseLlmClient.js +231 -0
- package/dist/src/core/baseLlmClient.js.map +1 -0
- package/dist/src/core/bucketFailoverIntegration.d.ts +62 -0
- package/dist/src/core/bucketFailoverIntegration.js +186 -0
- package/dist/src/core/bucketFailoverIntegration.js.map +1 -0
- package/dist/src/core/chatSession.d.ts +121 -0
- package/dist/src/core/chatSession.js +720 -0
- package/dist/src/core/chatSession.js.map +1 -0
- package/dist/src/core/client.d.ts +132 -0
- package/dist/src/core/client.js +524 -0
- package/dist/src/core/client.js.map +1 -0
- package/dist/src/core/clientHelpers.d.ts +15 -0
- package/dist/src/core/clientHelpers.js +122 -0
- package/dist/src/core/clientHelpers.js.map +1 -0
- package/dist/src/core/clientLlmUtilities.d.ts +30 -0
- package/dist/src/core/clientLlmUtilities.js +125 -0
- package/dist/src/core/clientLlmUtilities.js.map +1 -0
- package/dist/src/core/clientToolGovernance.d.ts +37 -0
- package/dist/src/core/clientToolGovernance.js +104 -0
- package/dist/src/core/clientToolGovernance.js.map +1 -0
- package/dist/src/core/compression-config.d.ts +12 -0
- package/dist/src/core/compression-config.js +21 -0
- package/dist/src/core/compression-config.js.map +1 -0
- package/dist/src/core/coreToolScheduler.d.ts +105 -0
- package/dist/src/core/coreToolScheduler.js +453 -0
- package/dist/src/core/coreToolScheduler.js.map +1 -0
- package/dist/src/core/hookToolRestrictions.d.ts +18 -0
- package/dist/src/core/hookToolRestrictions.js +187 -0
- package/dist/src/core/hookToolRestrictions.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +17 -0
- package/dist/src/core/nonInteractiveToolExecutor.js +102 -0
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -0
- package/dist/src/core/subagent.d.ts +105 -0
- package/dist/src/core/subagent.js +650 -0
- package/dist/src/core/subagent.js.map +1 -0
- package/dist/src/core/subagentExecution.d.ts +104 -0
- package/dist/src/core/subagentExecution.js +275 -0
- package/dist/src/core/subagentExecution.js.map +1 -0
- package/dist/src/core/subagentOrchestrator.d.ts +84 -0
- package/dist/src/core/subagentOrchestrator.js +503 -0
- package/dist/src/core/subagentOrchestrator.js.map +1 -0
- package/dist/src/core/subagentRuntimeSetup.d.ts +75 -0
- package/dist/src/core/subagentRuntimeSetup.js +387 -0
- package/dist/src/core/subagentRuntimeSetup.js.map +1 -0
- package/dist/src/core/subagentScheduler.d.ts +17 -0
- package/dist/src/core/subagentScheduler.js +7 -0
- package/dist/src/core/subagentScheduler.js.map +1 -0
- package/dist/src/core/subagentToolProcessing.d.ts +51 -0
- package/dist/src/core/subagentToolProcessing.js +359 -0
- package/dist/src/core/subagentToolProcessing.js.map +1 -0
- package/dist/src/core/toolGovernance.d.ts +18 -0
- package/dist/src/core/toolGovernance.js +50 -0
- package/dist/src/core/toolGovernance.js.map +1 -0
- package/dist/src/core/turn.d.ts +47 -0
- package/dist/src/core/turn.js +455 -0
- package/dist/src/core/turn.js.map +1 -0
- package/dist/src/core/turnLogging.d.ts +35 -0
- package/dist/src/core/turnLogging.js +80 -0
- package/dist/src/core/turnLogging.js.map +1 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.js +44 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/scheduler/confirmation-coordinator.d.ts +139 -0
- package/dist/src/scheduler/confirmation-coordinator.js +443 -0
- package/dist/src/scheduler/confirmation-coordinator.js.map +1 -0
- package/dist/src/scheduler/result-aggregator.d.ts +127 -0
- package/dist/src/scheduler/result-aggregator.js +302 -0
- package/dist/src/scheduler/result-aggregator.js.map +1 -0
- package/dist/src/scheduler/status-transitions.d.ts +39 -0
- package/dist/src/scheduler/status-transitions.js +184 -0
- package/dist/src/scheduler/status-transitions.js.map +1 -0
- package/dist/src/scheduler/tool-dispatcher.d.ts +40 -0
- package/dist/src/scheduler/tool-dispatcher.js +120 -0
- package/dist/src/scheduler/tool-dispatcher.js.map +1 -0
- package/dist/src/scheduler/tool-executor.d.ts +44 -0
- package/dist/src/scheduler/tool-executor.js +117 -0
- package/dist/src/scheduler/tool-executor.js.map +1 -0
- package/dist/src/scheduler/utils.d.ts +11 -0
- package/dist/src/scheduler/utils.js +19 -0
- package/dist/src/scheduler/utils.js.map +1 -0
- package/dist/src/tools/task.d.ts +128 -0
- package/dist/src/tools/task.js +932 -0
- package/dist/src/tools/task.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { GenerateContentResponse, Content, Part } from '@google/genai';
|
|
7
|
+
import type { ContentGenerator } from '@vybestack/llxprt-code-core/core/contentGenerator.js';
|
|
8
|
+
/**
|
|
9
|
+
* Options for generateJson method
|
|
10
|
+
*/
|
|
11
|
+
export interface GenerateJsonOptions {
|
|
12
|
+
prompt: string;
|
|
13
|
+
schema?: Record<string, unknown>;
|
|
14
|
+
model: string;
|
|
15
|
+
temperature?: number;
|
|
16
|
+
systemInstruction?: string;
|
|
17
|
+
promptId?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The maximum number of attempts for the request.
|
|
20
|
+
*/
|
|
21
|
+
maxAttempts?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Options for generateEmbedding method
|
|
25
|
+
*/
|
|
26
|
+
export interface GenerateEmbeddingOptions {
|
|
27
|
+
text: string | string[];
|
|
28
|
+
model: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Options for countTokens method
|
|
32
|
+
*/
|
|
33
|
+
export interface CountTokensOptions {
|
|
34
|
+
text?: string;
|
|
35
|
+
contents?: Content[];
|
|
36
|
+
model: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Options for the generateContent utility function.
|
|
40
|
+
*/
|
|
41
|
+
export interface GenerateContentOptions {
|
|
42
|
+
/** The input prompt or history. */
|
|
43
|
+
contents: Content[];
|
|
44
|
+
/** The model to use. */
|
|
45
|
+
model: string;
|
|
46
|
+
/**
|
|
47
|
+
* Task-specific system instructions.
|
|
48
|
+
* If omitted, no system instruction is sent.
|
|
49
|
+
*/
|
|
50
|
+
systemInstruction?: string | Part | Part[] | Content;
|
|
51
|
+
/** Signal for cancellation. */
|
|
52
|
+
abortSignal: AbortSignal;
|
|
53
|
+
/**
|
|
54
|
+
* A unique ID for the prompt, used for logging/telemetry correlation.
|
|
55
|
+
*/
|
|
56
|
+
promptId: string;
|
|
57
|
+
/**
|
|
58
|
+
* The maximum number of attempts for the request.
|
|
59
|
+
*/
|
|
60
|
+
maxAttempts?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* BaseLLMClient extracts stateless utility methods for LLM operations.
|
|
64
|
+
* Unlike the main Client class, this handles utility calls without conversation state.
|
|
65
|
+
*
|
|
66
|
+
* This implements the baseLlmClient pattern from upstream gemini-cli but adapted
|
|
67
|
+
* for llxprt's multi-provider architecture.
|
|
68
|
+
*
|
|
69
|
+
* Key features:
|
|
70
|
+
* - Multi-provider support (Anthropic, OpenAI, Gemini, Vertex AI)
|
|
71
|
+
* - Stateless operations (no conversation history)
|
|
72
|
+
* - Clean separation from AgentClient
|
|
73
|
+
* - Dependency injection for testing
|
|
74
|
+
*/
|
|
75
|
+
export declare class BaseLLMClient {
|
|
76
|
+
private readonly contentGenerator;
|
|
77
|
+
constructor(contentGenerator: ContentGenerator | null);
|
|
78
|
+
/**
|
|
79
|
+
* Generate structured JSON from a prompt with optional schema validation.
|
|
80
|
+
* Supports all providers through the ContentGenerator abstraction.
|
|
81
|
+
*
|
|
82
|
+
* @param options - Generation options including prompt, schema, model, etc.
|
|
83
|
+
* @returns Parsed JSON object
|
|
84
|
+
* @throws Error if generation fails or response cannot be parsed
|
|
85
|
+
*/
|
|
86
|
+
generateJson<T = unknown>(options: GenerateJsonOptions): Promise<T>;
|
|
87
|
+
/**
|
|
88
|
+
* Generate embeddings for text input.
|
|
89
|
+
* Supports single text string or array of strings.
|
|
90
|
+
*
|
|
91
|
+
* @param options - Embedding options including text and model
|
|
92
|
+
* @returns Embedding vector(s) as number array(s)
|
|
93
|
+
* @throws Error if generation fails or response is invalid
|
|
94
|
+
*/
|
|
95
|
+
generateEmbedding(options: GenerateEmbeddingOptions): Promise<number[] | number[][]>;
|
|
96
|
+
/**
|
|
97
|
+
* Count tokens in text or contents without making an API call to generate.
|
|
98
|
+
* Useful for checking context limits before generation.
|
|
99
|
+
*
|
|
100
|
+
* @param options - Options including text/contents and model
|
|
101
|
+
* @returns Token count
|
|
102
|
+
* @throws Error if counting fails
|
|
103
|
+
*/
|
|
104
|
+
countTokens(options: CountTokensOptions): Promise<number>;
|
|
105
|
+
/**
|
|
106
|
+
* Generate content from a prompt.
|
|
107
|
+
* This is a general-purpose content generation method that doesn't enforce JSON output.
|
|
108
|
+
*
|
|
109
|
+
* @param options - Generation options
|
|
110
|
+
* @returns Raw GenerateContentResponse
|
|
111
|
+
* @throws Error if generation fails
|
|
112
|
+
*/
|
|
113
|
+
generateContent(options: GenerateContentOptions): Promise<GenerateContentResponse>;
|
|
114
|
+
private _generateWithRetry;
|
|
115
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { getResponseText } from '@vybestack/llxprt-code-core/utils/generateContentResponseUtilities.js';
|
|
7
|
+
import { getErrorMessage } from '@vybestack/llxprt-code-core/utils/errors.js';
|
|
8
|
+
import { retryWithBackoff } from '@vybestack/llxprt-code-core/utils/retry.js';
|
|
9
|
+
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
10
|
+
/**
|
|
11
|
+
* Extracts JSON from a string that might be wrapped in markdown code blocks
|
|
12
|
+
* @param text - The raw text that might contain markdown-wrapped JSON
|
|
13
|
+
* @returns The extracted JSON string or the original text if no markdown found
|
|
14
|
+
*/
|
|
15
|
+
function extractJsonFromMarkdown(text) {
|
|
16
|
+
// Try to match ```json ... ``` or ``` ... ```
|
|
17
|
+
// eslint-disable-next-line sonarjs/regular-expr, sonarjs/slow-regex -- Static regex reviewed for lint hardening; bounded inputs preserve behavior.
|
|
18
|
+
const markdownMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
19
|
+
if (markdownMatch?.[1]) {
|
|
20
|
+
return markdownMatch[1].trim();
|
|
21
|
+
}
|
|
22
|
+
// If no markdown found, return trimmed original text
|
|
23
|
+
return text.trim();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* BaseLLMClient extracts stateless utility methods for LLM operations.
|
|
27
|
+
* Unlike the main Client class, this handles utility calls without conversation state.
|
|
28
|
+
*
|
|
29
|
+
* This implements the baseLlmClient pattern from upstream gemini-cli but adapted
|
|
30
|
+
* for llxprt's multi-provider architecture.
|
|
31
|
+
*
|
|
32
|
+
* Key features:
|
|
33
|
+
* - Multi-provider support (Anthropic, OpenAI, Gemini, Vertex AI)
|
|
34
|
+
* - Stateless operations (no conversation history)
|
|
35
|
+
* - Clean separation from AgentClient
|
|
36
|
+
* - Dependency injection for testing
|
|
37
|
+
*/
|
|
38
|
+
export class BaseLLMClient {
|
|
39
|
+
contentGenerator;
|
|
40
|
+
constructor(contentGenerator) {
|
|
41
|
+
this.contentGenerator = contentGenerator;
|
|
42
|
+
if (!contentGenerator) {
|
|
43
|
+
throw new Error('ContentGenerator is required');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate structured JSON from a prompt with optional schema validation.
|
|
48
|
+
* Supports all providers through the ContentGenerator abstraction.
|
|
49
|
+
*
|
|
50
|
+
* @param options - Generation options including prompt, schema, model, etc.
|
|
51
|
+
* @returns Parsed JSON object
|
|
52
|
+
* @throws Error if generation fails or response cannot be parsed
|
|
53
|
+
*/
|
|
54
|
+
async generateJson(options) {
|
|
55
|
+
const { prompt, schema, model, temperature = 0, systemInstruction, promptId = 'baseLlmClient-generateJson', } = options;
|
|
56
|
+
const contents = [
|
|
57
|
+
{
|
|
58
|
+
role: 'user',
|
|
59
|
+
parts: [{ text: prompt }],
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
const config = {
|
|
63
|
+
temperature,
|
|
64
|
+
topP: 1,
|
|
65
|
+
};
|
|
66
|
+
if (systemInstruction) {
|
|
67
|
+
config.systemInstruction = { text: systemInstruction };
|
|
68
|
+
}
|
|
69
|
+
if (schema) {
|
|
70
|
+
config.responseJsonSchema = schema;
|
|
71
|
+
config.responseMimeType = 'application/json';
|
|
72
|
+
}
|
|
73
|
+
const shouldRetryOnContent = (response) => {
|
|
74
|
+
const text = getResponseText(response)?.trim();
|
|
75
|
+
if (!text) {
|
|
76
|
+
return true; // Retry on empty response
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
// Extract JSON from potential markdown wrapper
|
|
80
|
+
const cleanedText = extractJsonFromMarkdown(text);
|
|
81
|
+
JSON.parse(cleanedText);
|
|
82
|
+
return false; // Valid JSON, don't retry
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Invalid JSON - trigger retry
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const result = await this._generateWithRetry({
|
|
90
|
+
model,
|
|
91
|
+
contents,
|
|
92
|
+
config,
|
|
93
|
+
}, promptId, options.maxAttempts, shouldRetryOnContent, 'generateJson');
|
|
94
|
+
let text = getResponseText(result);
|
|
95
|
+
if (!text) {
|
|
96
|
+
throw new Error('API returned an empty response for generateJson.');
|
|
97
|
+
}
|
|
98
|
+
// Handle markdown wrapping
|
|
99
|
+
const prefix = '```json';
|
|
100
|
+
const suffix = '```';
|
|
101
|
+
if (text.startsWith(prefix) && text.endsWith(suffix)) {
|
|
102
|
+
text = text.substring(prefix.length, text.length - suffix.length).trim();
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
// Extract JSON from potential markdown wrapper
|
|
106
|
+
const cleanedText = extractJsonFromMarkdown(text);
|
|
107
|
+
return JSON.parse(cleanedText);
|
|
108
|
+
}
|
|
109
|
+
catch (parseError) {
|
|
110
|
+
throw new Error(`Failed to parse API response as JSON: ${getErrorMessage(parseError)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Generate embeddings for text input.
|
|
115
|
+
* Supports single text string or array of strings.
|
|
116
|
+
*
|
|
117
|
+
* @param options - Embedding options including text and model
|
|
118
|
+
* @returns Embedding vector(s) as number array(s)
|
|
119
|
+
* @throws Error if generation fails or response is invalid
|
|
120
|
+
*/
|
|
121
|
+
async generateEmbedding(options) {
|
|
122
|
+
const { text, model } = options;
|
|
123
|
+
try {
|
|
124
|
+
const texts = Array.isArray(text) ? text : [text];
|
|
125
|
+
const embedContentResponse = await this.contentGenerator.embedContent({
|
|
126
|
+
model,
|
|
127
|
+
contents: texts,
|
|
128
|
+
});
|
|
129
|
+
if (!embedContentResponse.embeddings ||
|
|
130
|
+
embedContentResponse.embeddings.length === 0) {
|
|
131
|
+
throw new Error('No embeddings found in API response.');
|
|
132
|
+
}
|
|
133
|
+
if (embedContentResponse.embeddings.length !== texts.length) {
|
|
134
|
+
throw new Error(`API returned a mismatched number of embeddings. Expected ${texts.length}, got ${embedContentResponse.embeddings.length}.`);
|
|
135
|
+
}
|
|
136
|
+
const embeddings = embedContentResponse.embeddings.map((embedding, index) => {
|
|
137
|
+
const values = embedding.values;
|
|
138
|
+
if (!values || values.length === 0) {
|
|
139
|
+
throw new Error(`API returned an empty embedding for input text at index ${index}: "${texts[index]}"`);
|
|
140
|
+
}
|
|
141
|
+
return values;
|
|
142
|
+
});
|
|
143
|
+
// Return single array if input was a single string
|
|
144
|
+
return Array.isArray(text) ? embeddings : embeddings[0];
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
throw new Error(`Failed to generate embedding: ${getErrorMessage(error)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Count tokens in text or contents without making an API call to generate.
|
|
152
|
+
* Useful for checking context limits before generation.
|
|
153
|
+
*
|
|
154
|
+
* @param options - Options including text/contents and model
|
|
155
|
+
* @returns Token count
|
|
156
|
+
* @throws Error if counting fails
|
|
157
|
+
*/
|
|
158
|
+
async countTokens(options) {
|
|
159
|
+
const { text, contents, model } = options;
|
|
160
|
+
try {
|
|
161
|
+
let requestContents;
|
|
162
|
+
if (contents) {
|
|
163
|
+
requestContents = contents;
|
|
164
|
+
}
|
|
165
|
+
else if (text) {
|
|
166
|
+
requestContents = [
|
|
167
|
+
{
|
|
168
|
+
role: 'user',
|
|
169
|
+
parts: [{ text }],
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
throw new Error('Either text or contents must be provided');
|
|
175
|
+
}
|
|
176
|
+
const response = await this.contentGenerator.countTokens({
|
|
177
|
+
model,
|
|
178
|
+
contents: requestContents,
|
|
179
|
+
});
|
|
180
|
+
return response.totalTokens ?? 0;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new Error(`Failed to count tokens: ${getErrorMessage(error)}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Generate content from a prompt.
|
|
188
|
+
* This is a general-purpose content generation method that doesn't enforce JSON output.
|
|
189
|
+
*
|
|
190
|
+
* @param options - Generation options
|
|
191
|
+
* @returns Raw GenerateContentResponse
|
|
192
|
+
* @throws Error if generation fails
|
|
193
|
+
*/
|
|
194
|
+
async generateContent(options) {
|
|
195
|
+
const { contents, model, systemInstruction, abortSignal, promptId, maxAttempts, } = options;
|
|
196
|
+
const config = {
|
|
197
|
+
temperature: 0,
|
|
198
|
+
topP: 1,
|
|
199
|
+
abortSignal,
|
|
200
|
+
};
|
|
201
|
+
if (systemInstruction !== undefined && systemInstruction !== '') {
|
|
202
|
+
config.systemInstruction = systemInstruction;
|
|
203
|
+
}
|
|
204
|
+
const shouldRetryOnContent = (response) => {
|
|
205
|
+
const text = getResponseText(response)?.trim();
|
|
206
|
+
return !text; // Retry on empty response
|
|
207
|
+
};
|
|
208
|
+
return this._generateWithRetry({
|
|
209
|
+
model,
|
|
210
|
+
contents,
|
|
211
|
+
config,
|
|
212
|
+
}, promptId, maxAttempts, shouldRetryOnContent, 'generateContent');
|
|
213
|
+
}
|
|
214
|
+
async _generateWithRetry(requestParams, promptId, maxAttempts, shouldRetryOnContent, _errorContext) {
|
|
215
|
+
const abortSignal = requestParams.config?.abortSignal;
|
|
216
|
+
try {
|
|
217
|
+
const apiCall = () => this.contentGenerator.generateContent(requestParams, promptId);
|
|
218
|
+
return await retryWithBackoff(apiCall, {
|
|
219
|
+
shouldRetryOnContent,
|
|
220
|
+
maxAttempts: maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (abortSignal?.aborted === true) {
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
throw new Error(`Failed to generate content: ${getErrorMessage(error)}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=baseLlmClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseLlmClient.js","sourceRoot":"","sources":["../../../src/core/baseLlmClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* @plan PLAN-20251213issue490
|
|
7
|
+
* Phase 7: Bucket Failover Integration
|
|
8
|
+
*
|
|
9
|
+
* Integrates bucket failover logic into ChatSession provider execution flow
|
|
10
|
+
*/
|
|
11
|
+
import type { IContent, ContentBlock } from '@vybestack/llxprt-code-core/services/history/IContent.js';
|
|
12
|
+
import type { RuntimeProvider as IProvider } from '@vybestack/llxprt-code-core/runtime/contracts/RuntimeProvider.js';
|
|
13
|
+
import type { RuntimeGenerateChatOptions as GenerateChatOptions } from '@vybestack/llxprt-code-core/runtime/contracts/RuntimeProviderChat.js';
|
|
14
|
+
/**
|
|
15
|
+
* Configuration for bucket failover execution
|
|
16
|
+
*/
|
|
17
|
+
export interface BucketFailoverConfig {
|
|
18
|
+
buckets: string[];
|
|
19
|
+
provider: IProvider;
|
|
20
|
+
tokenRefreshCallback?: (bucket: string) => Promise<void>;
|
|
21
|
+
notificationCallback?: (fromBucket: string, toBucket: string) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Result from bucket failover execution including which bucket succeeded
|
|
25
|
+
*/
|
|
26
|
+
export interface BucketFailoverResult {
|
|
27
|
+
content: IContent;
|
|
28
|
+
bucket: string;
|
|
29
|
+
attemptedBuckets: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Wrapper for provider generateChatCompletion that handles bucket failover
|
|
33
|
+
*
|
|
34
|
+
* When multiple OAuth buckets are configured, this will automatically retry
|
|
35
|
+
* failed requests (429/quota/402 errors) with the next available bucket.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Chat generation options to pass to provider
|
|
38
|
+
* @param config - Bucket failover configuration
|
|
39
|
+
* @returns The final IContent response and which bucket succeeded
|
|
40
|
+
* @throws Error if all buckets are exhausted
|
|
41
|
+
*/
|
|
42
|
+
export declare function executeProviderWithBucketFailover(options: GenerateChatOptions, config: BucketFailoverConfig): Promise<BucketFailoverResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if bucket failover should be enabled for the current configuration
|
|
45
|
+
*
|
|
46
|
+
* Bucket failover is enabled when:
|
|
47
|
+
* 1. Profile has auth configuration
|
|
48
|
+
* 2. Auth type is 'oauth'
|
|
49
|
+
* 3. Multiple buckets are configured
|
|
50
|
+
*
|
|
51
|
+
* @param authConfig - The profile's auth configuration
|
|
52
|
+
* @returns true if failover should be enabled
|
|
53
|
+
*/
|
|
54
|
+
export declare function shouldEnableBucketFailover(authConfig: {
|
|
55
|
+
type: string;
|
|
56
|
+
buckets?: string[];
|
|
57
|
+
} | undefined): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Aggregate text content from IContent blocks
|
|
60
|
+
* Helper to extract text from provider responses
|
|
61
|
+
*/
|
|
62
|
+
export declare function aggregateTextFromBlocks(blocks: ContentBlock[]): string;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* @plan PLAN-20251213issue490
|
|
7
|
+
* Phase 7: Bucket Failover Integration
|
|
8
|
+
*
|
|
9
|
+
* Integrates bucket failover logic into ChatSession provider execution flow
|
|
10
|
+
*/
|
|
11
|
+
import { DebugLogger } from '@vybestack/llxprt-code-core/debug/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Determines if an error should trigger failover to the next bucket
|
|
14
|
+
*
|
|
15
|
+
* Failover triggers:
|
|
16
|
+
* - 429 rate limit
|
|
17
|
+
* - Quota exceeded
|
|
18
|
+
* - 402 payment required
|
|
19
|
+
* - Token renewal failure
|
|
20
|
+
*
|
|
21
|
+
* Does NOT failover:
|
|
22
|
+
* - 400 bad request
|
|
23
|
+
* - Other API errors
|
|
24
|
+
*/
|
|
25
|
+
function shouldFailover(error) {
|
|
26
|
+
const message = error.message.toLowerCase();
|
|
27
|
+
// Check for status code on error object (common pattern)
|
|
28
|
+
const errorStatus = error.status;
|
|
29
|
+
if (errorStatus === 401 || errorStatus === 403) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
// Check for Anthropic body-level error types (rate_limit_error, overloaded_error)
|
|
33
|
+
const bodyError = error;
|
|
34
|
+
if (bodyError.error?.type === 'rate_limit_error' ||
|
|
35
|
+
bodyError.error?.type === 'overloaded_error') {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return (
|
|
39
|
+
// eslint-disable-next-line sonarjs/expression-complexity -- Existing structure is intentionally preserved; refactoring this boundary is outside the lint slice.
|
|
40
|
+
message.includes('429') ||
|
|
41
|
+
message.includes('401') ||
|
|
42
|
+
message.includes('403') ||
|
|
43
|
+
message.includes('rate limit') ||
|
|
44
|
+
message.includes('quota') ||
|
|
45
|
+
message.includes('402') ||
|
|
46
|
+
message.includes('payment') ||
|
|
47
|
+
message.includes('revoked') ||
|
|
48
|
+
message.includes('permission_error') ||
|
|
49
|
+
(message.includes('token') && message.includes('expired')));
|
|
50
|
+
}
|
|
51
|
+
const logger = new DebugLogger('llxprt:bucket:failover:integration');
|
|
52
|
+
/**
|
|
53
|
+
* Wrapper for provider generateChatCompletion that handles bucket failover
|
|
54
|
+
*
|
|
55
|
+
* When multiple OAuth buckets are configured, this will automatically retry
|
|
56
|
+
* failed requests (429/quota/402 errors) with the next available bucket.
|
|
57
|
+
*
|
|
58
|
+
* @param options - Chat generation options to pass to provider
|
|
59
|
+
* @param config - Bucket failover configuration
|
|
60
|
+
* @returns The final IContent response and which bucket succeeded
|
|
61
|
+
* @throws Error if all buckets are exhausted
|
|
62
|
+
*/
|
|
63
|
+
export async function executeProviderWithBucketFailover(options, config) {
|
|
64
|
+
const { buckets, provider, tokenRefreshCallback, notificationCallback } = config;
|
|
65
|
+
if (buckets.length === 0) {
|
|
66
|
+
throw new Error('Bucket failover requires at least one bucket');
|
|
67
|
+
}
|
|
68
|
+
if (typeof provider.generateChatCompletion !== 'function') {
|
|
69
|
+
throw new Error('Provider does not support generateChatCompletion');
|
|
70
|
+
}
|
|
71
|
+
const attemptedBuckets = [];
|
|
72
|
+
let lastError = null;
|
|
73
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
74
|
+
const bucket = buckets[i];
|
|
75
|
+
attemptedBuckets.push(bucket);
|
|
76
|
+
try {
|
|
77
|
+
// Refresh token for this bucket if callback provided
|
|
78
|
+
if (tokenRefreshCallback) {
|
|
79
|
+
logger.debug(() => `Refreshing OAuth token for bucket '${bucket}'`);
|
|
80
|
+
await tokenRefreshCallback(bucket);
|
|
81
|
+
}
|
|
82
|
+
logger.debug(() => `Attempting provider call with bucket '${bucket}' (${i + 1}/${buckets.length})`);
|
|
83
|
+
// Call provider with current bucket's auth
|
|
84
|
+
const stream = provider.generateChatCompletion(options);
|
|
85
|
+
// Consume the async generator to get the final result
|
|
86
|
+
let lastContent;
|
|
87
|
+
for await (const chunk of stream) {
|
|
88
|
+
lastContent = chunk;
|
|
89
|
+
}
|
|
90
|
+
if (!lastContent) {
|
|
91
|
+
throw new Error('Provider returned empty response');
|
|
92
|
+
}
|
|
93
|
+
logger.debug(() => `Successfully completed request with bucket '${bucket}'`);
|
|
94
|
+
return {
|
|
95
|
+
content: lastContent,
|
|
96
|
+
bucket,
|
|
97
|
+
attemptedBuckets,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
const err = error;
|
|
102
|
+
lastError = err;
|
|
103
|
+
logger.debug(() => `Bucket '${bucket}' failed with error: ${err.message}`);
|
|
104
|
+
// Check if this error should trigger failover
|
|
105
|
+
if (shouldFailover(err)) {
|
|
106
|
+
// eslint-disable-next-line sonarjs/nested-control-flow -- Existing structure is intentionally preserved; refactoring this boundary is outside the lint slice.
|
|
107
|
+
if (i < buckets.length - 1) {
|
|
108
|
+
const nextBucket = buckets[i + 1];
|
|
109
|
+
// Notify about bucket switch
|
|
110
|
+
if (notificationCallback) {
|
|
111
|
+
notificationCallback(bucket, nextBucket);
|
|
112
|
+
}
|
|
113
|
+
logger.debug(() => `Failing over from bucket '${bucket}' to '${nextBucket}'`);
|
|
114
|
+
// Continue to next bucket
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// Last bucket also failed with failover error
|
|
119
|
+
const exhaustedMessage = formatAllBucketsExhaustedError(provider.name, buckets, attemptedBuckets, lastError);
|
|
120
|
+
throw new Error(exhaustedMessage);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Non-failover error - throw immediately
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Should never reach here, but handle the case
|
|
128
|
+
const exhaustedMessage = formatAllBucketsExhaustedError(provider.name, buckets, attemptedBuckets, lastError);
|
|
129
|
+
throw new Error(exhaustedMessage);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Format comprehensive error message when all buckets are exhausted
|
|
133
|
+
*/
|
|
134
|
+
function formatAllBucketsExhaustedError(providerName, allBuckets, attemptedBuckets, lastError) {
|
|
135
|
+
let message = `All buckets exhausted for provider '${providerName}':\n`;
|
|
136
|
+
for (const bucket of attemptedBuckets) {
|
|
137
|
+
message += ` - ${bucket}: failed\n`;
|
|
138
|
+
}
|
|
139
|
+
// Note any buckets that weren't tried
|
|
140
|
+
const unattempted = allBuckets.filter((b) => !attemptedBuckets.includes(b));
|
|
141
|
+
if (unattempted.length > 0) {
|
|
142
|
+
message += `\nUnattempted buckets: ${unattempted.join(', ')}\n`;
|
|
143
|
+
}
|
|
144
|
+
if (lastError) {
|
|
145
|
+
message += `\nLast error: ${lastError.message}`;
|
|
146
|
+
}
|
|
147
|
+
message += `\n\nTry again later or add more OAuth buckets to the profile.`;
|
|
148
|
+
return message;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if bucket failover should be enabled for the current configuration
|
|
152
|
+
*
|
|
153
|
+
* Bucket failover is enabled when:
|
|
154
|
+
* 1. Profile has auth configuration
|
|
155
|
+
* 2. Auth type is 'oauth'
|
|
156
|
+
* 3. Multiple buckets are configured
|
|
157
|
+
*
|
|
158
|
+
* @param authConfig - The profile's auth configuration
|
|
159
|
+
* @returns true if failover should be enabled
|
|
160
|
+
*/
|
|
161
|
+
export function shouldEnableBucketFailover(authConfig) {
|
|
162
|
+
if (!authConfig) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (authConfig.type !== 'oauth') {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (!authConfig.buckets || authConfig.buckets.length <= 1) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Aggregate text content from IContent blocks
|
|
175
|
+
* Helper to extract text from provider responses
|
|
176
|
+
*/
|
|
177
|
+
export function aggregateTextFromBlocks(blocks) {
|
|
178
|
+
let text = '';
|
|
179
|
+
for (const block of blocks) {
|
|
180
|
+
if (block.type === 'text') {
|
|
181
|
+
text += block.text;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return text;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=bucketFailoverIntegration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bucketFailoverIntegration.js","sourceRoot":"","sources":["../../../src/core/bucketFailoverIntegration.ts"],"names":[],"mappings":"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"}
|