This commit introduces two key improvements:
1. **Google Provider Telemetry:**
- Updated to include token usage data (, ) in the responses from and .
- This aligns the Google provider with others for consistent AI usage telemetry.
2. **Robust AI Object Response Handling:**
- Modified to more flexibly handle responses from .
- The add-task module now check for the AI-generated object in both and , improving compatibility with different AI provider response structures (e.g., Gemini).
These changes enhance the reliability of AI interactions, particularly with the Google provider, and ensure accurate telemetry collection.
184 lines
6.4 KiB
JavaScript
184 lines
6.4 KiB
JavaScript
/**
|
|
* google.js
|
|
* AI provider implementation for Google AI models (e.g., Gemini) using Vercel AI SDK.
|
|
*/
|
|
|
|
// import { GoogleGenerativeAI } from '@ai-sdk/google'; // Incorrect import
|
|
import { createGoogleGenerativeAI } from '@ai-sdk/google'; // Correct import for customization
|
|
import { generateText, streamText, generateObject } from 'ai'; // Import from main 'ai' package
|
|
import { log } from '../../scripts/modules/utils.js'; // Import logging utility
|
|
|
|
// Consider making model configurable via config-manager.js later
|
|
const DEFAULT_MODEL = 'gemini-2.5-pro-exp-03-25'; // Or a suitable default
|
|
const DEFAULT_TEMPERATURE = 0.2; // Or a suitable default
|
|
|
|
/**
|
|
* Generates text using a Google AI model.
|
|
*
|
|
* @param {object} params - Parameters for the generation.
|
|
* @param {string} params.apiKey - Google API Key.
|
|
* @param {string} params.modelId - Specific model ID to use (overrides default).
|
|
* @param {number} params.temperature - Generation temperature.
|
|
* @param {Array<object>} params.messages - The conversation history (system/user prompts).
|
|
* @param {number} [params.maxTokens] - Optional max tokens.
|
|
* @returns {Promise<string>} The generated text content.
|
|
* @throws {Error} If API key is missing or API call fails.
|
|
*/
|
|
async function generateGoogleText({
|
|
apiKey,
|
|
modelId = DEFAULT_MODEL,
|
|
temperature = DEFAULT_TEMPERATURE,
|
|
messages,
|
|
maxTokens // Note: Vercel SDK might handle this differently, needs verification
|
|
}) {
|
|
if (!apiKey) {
|
|
throw new Error('Google API key is required.');
|
|
}
|
|
log('info', `Generating text with Google model: ${modelId}`);
|
|
|
|
try {
|
|
// const google = new GoogleGenerativeAI({ apiKey }); // Incorrect instantiation
|
|
const googleProvider = createGoogleGenerativeAI({ apiKey }); // Correct instantiation
|
|
// const model = google.getGenerativeModel({ model: modelId }); // Incorrect model retrieval
|
|
const model = googleProvider(modelId); // Correct model retrieval
|
|
|
|
// Construct payload suitable for Vercel SDK's generateText
|
|
// Note: The exact structure might depend on how messages are passed
|
|
const result = await generateText({
|
|
model, // Pass the model instance
|
|
messages, // Pass the messages array directly
|
|
temperature,
|
|
maxOutputTokens: maxTokens // Map to correct Vercel SDK param if available
|
|
});
|
|
|
|
// Assuming result structure provides text directly or within a property
|
|
// return result.text; // Adjust based on actual SDK response
|
|
// Return both text and usage
|
|
return {
|
|
text: result.text,
|
|
usage: {
|
|
inputTokens: result.usage.promptTokens,
|
|
outputTokens: result.usage.completionTokens
|
|
}
|
|
};
|
|
} catch (error) {
|
|
log(
|
|
'error',
|
|
`Error generating text with Google (${modelId}): ${error.message}`
|
|
);
|
|
throw error; // Re-throw for unified service handler
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Streams text using a Google AI model.
|
|
*
|
|
* @param {object} params - Parameters for the streaming.
|
|
* @param {string} params.apiKey - Google API Key.
|
|
* @param {string} params.modelId - Specific model ID to use (overrides default).
|
|
* @param {number} params.temperature - Generation temperature.
|
|
* @param {Array<object>} params.messages - The conversation history.
|
|
* @param {number} [params.maxTokens] - Optional max tokens.
|
|
* @returns {Promise<ReadableStream>} A readable stream of text deltas.
|
|
* @throws {Error} If API key is missing or API call fails.
|
|
*/
|
|
async function streamGoogleText({
|
|
apiKey,
|
|
modelId = DEFAULT_MODEL,
|
|
temperature = DEFAULT_TEMPERATURE,
|
|
messages,
|
|
maxTokens
|
|
}) {
|
|
if (!apiKey) {
|
|
throw new Error('Google API key is required.');
|
|
}
|
|
log('info', `Streaming text with Google model: ${modelId}`);
|
|
|
|
try {
|
|
// const google = new GoogleGenerativeAI({ apiKey }); // Incorrect instantiation
|
|
const googleProvider = createGoogleGenerativeAI({ apiKey }); // Correct instantiation
|
|
// const model = google.getGenerativeModel({ model: modelId }); // Incorrect model retrieval
|
|
const model = googleProvider(modelId); // Correct model retrieval
|
|
|
|
const stream = await streamText({
|
|
model, // Pass the model instance
|
|
messages,
|
|
temperature,
|
|
maxOutputTokens: maxTokens
|
|
});
|
|
|
|
return stream; // Return the stream directly
|
|
} catch (error) {
|
|
log(
|
|
'error',
|
|
`Error streaming text with Google (${modelId}): ${error.message}`
|
|
);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a structured object using a Google AI model.
|
|
*
|
|
* @param {object} params - Parameters for the object generation.
|
|
* @param {string} params.apiKey - Google API Key.
|
|
* @param {string} params.modelId - Specific model ID to use (overrides default).
|
|
* @param {number} params.temperature - Generation temperature.
|
|
* @param {Array<object>} params.messages - The conversation history.
|
|
* @param {import('zod').ZodSchema} params.schema - Zod schema for the expected object.
|
|
* @param {string} params.objectName - Name for the object generation context.
|
|
* @param {number} [params.maxTokens] - Optional max tokens.
|
|
* @returns {Promise<object>} The generated object matching the schema.
|
|
* @throws {Error} If API key is missing or API call fails.
|
|
*/
|
|
async function generateGoogleObject({
|
|
apiKey,
|
|
modelId = DEFAULT_MODEL,
|
|
temperature = DEFAULT_TEMPERATURE,
|
|
messages,
|
|
schema,
|
|
objectName, // Note: Vercel SDK might use this differently or not at all
|
|
maxTokens
|
|
}) {
|
|
if (!apiKey) {
|
|
throw new Error('Google API key is required.');
|
|
}
|
|
log('info', `Generating object with Google model: ${modelId}`);
|
|
|
|
try {
|
|
// const google = new GoogleGenerativeAI({ apiKey }); // Incorrect instantiation
|
|
const googleProvider = createGoogleGenerativeAI({ apiKey }); // Correct instantiation
|
|
// const model = google.getGenerativeModel({ model: modelId }); // Incorrect model retrieval
|
|
const model = googleProvider(modelId); // Correct model retrieval
|
|
|
|
const result = await generateObject({
|
|
model, // Pass the model instance
|
|
schema,
|
|
messages,
|
|
temperature,
|
|
maxOutputTokens: maxTokens
|
|
// Note: 'objectName' or 'mode' might not be directly applicable here
|
|
// depending on how `@ai-sdk/google` handles `generateObject`.
|
|
// Check SDK docs if specific tool calling/JSON mode needs explicit setup.
|
|
});
|
|
|
|
// return object; // Return the parsed object
|
|
// Return both object and usage
|
|
return {
|
|
object: result.object,
|
|
usage: {
|
|
inputTokens: result.usage.promptTokens,
|
|
outputTokens: result.usage.completionTokens
|
|
}
|
|
};
|
|
} catch (error) {
|
|
log(
|
|
'error',
|
|
`Error generating object with Google (${modelId}): ${error.message}`
|
|
);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export { generateGoogleText, streamGoogleText, generateGoogleObject };
|