--- description: Guidelines for interacting with the unified AI service layer. globs: scripts/modules/ai-services-unified.js, scripts/modules/task-manager/*.js, scripts/modules/commands.js --- # AI Services Layer Guidelines This document outlines the architecture and usage patterns for interacting with Large Language Models (LLMs) via Task Master's unified AI service layer (`ai-services-unified.js`). The goal is to centralize configuration, provider selection, API key management, fallback logic, and error handling. **Core Components:** * **Configuration (`.taskmasterconfig` & [`config-manager.js`](mdc:scripts/modules/config-manager.js)):** * Defines the AI provider and model ID for different **roles** (`main`, `research`, `fallback`). * Stores parameters like `maxTokens` and `temperature` per role. * Managed via the `task-master models --setup` CLI command. * [`config-manager.js`](mdc:scripts/modules/config-manager.js) provides **getters** (e.g., `getMainProvider()`, `getParametersForRole()`) to access these settings. Core logic should **only** use these getters for *non-AI related application logic* (e.g., `getDefaultSubtasks`). The unified service fetches necessary AI parameters internally based on the `role`. * **API keys** are **NOT** stored here; they are resolved via `resolveEnvVariable` (in [`utils.js`](mdc:scripts/modules/utils.js)) from `.env` (for CLI) or the MCP `session.env` object (for MCP calls). See [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc) and [`dev_workflow.mdc`](mdc:.cursor/rules/dev_workflow.mdc). * **Unified Service (`ai-services-unified.js`):** * Exports primary interaction functions: `generateTextService`, `generateObjectService`. (Note: `streamTextService` exists but has known reliability issues with some providers/payloads). * Contains the core `_unifiedServiceRunner` logic. * Internally uses `config-manager.js` getters to determine the provider/model/parameters based on the requested `role`. * Implements the **fallback sequence** (e.g., main -> fallback -> research) if the primary provider/model fails. * Constructs the `messages` array required by the Vercel AI SDK. * Implements **retry logic** for specific API errors (`_attemptProviderCallWithRetries`). * Resolves API keys automatically via `_resolveApiKey` (using `resolveEnvVariable`). * Maps requests to the correct provider implementation (in `src/ai-providers/`) via `PROVIDER_FUNCTIONS`. * Returns a structured object containing the primary AI result (`mainResult`) and telemetry data (`telemetryData`). See [`telemetry.mdc`](mdc:.cursor/rules/telemetry.mdc) for details on how this telemetry data is propagated and handled. * **Provider Implementations (`src/ai-providers/*.js`):** * Contain provider-specific wrappers around Vercel AI SDK functions (`generateText`, `generateObject`). **Usage Pattern (from Core Logic like `task-manager/*.js`):** 1. **Import Service:** Import `generateTextService` or `generateObjectService` from `../ai-services-unified.js`. ```javascript // Preferred for most tasks (especially with complex JSON) import { generateTextService } from '../ai-services-unified.js'; // Use if structured output is reliable for the specific use case // import { generateObjectService } from '../ai-services-unified.js'; ``` 2. **Prepare Parameters:** Construct the parameters object for the service call. * `role`: **Required.** `'main'`, `'research'`, or `'fallback'`. Determines the initial provider/model/parameters used by the unified service. * `session`: **Required if called from MCP context.** Pass the `session` object received by the direct function wrapper. The unified service uses `session.env` to find API keys. * `systemPrompt`: Your system instruction string. * `prompt`: The user message string (can be long, include stringified data, etc.). * (For `generateObjectService` only): `schema` (Zod schema), `objectName`. 3. **Call Service:** Use `await` to call the service function. ```javascript // Example using generateTextService (most common) try { const resultText = await generateTextService({ role: useResearch ? 'research' : 'main', // Determine role based on logic session: context.session, // Pass session from context object systemPrompt: "You are...", prompt: userMessageContent }); // Process the raw text response (e.g., parse JSON, use directly) // ... } catch (error) { // Handle errors thrown by the unified service (if all fallbacks/retries fail) report('error', `Unified AI service call failed: ${error.message}`); throw error; } // Example using generateObjectService (use cautiously) try { const resultObject = await generateObjectService({ role: 'main', session: context.session, schema: myZodSchema, objectName: 'myDataObject', systemPrompt: "You are...", prompt: userMessageContent }); // resultObject is already a validated JS object // ... } catch (error) { report('error', `Unified AI service call failed: ${error.message}`); throw error; } ``` 4. **Handle Results/Errors:** Process the returned text/object or handle errors thrown by the unified service layer. **Key Implementation Rules & Gotchas:** * ✅ **DO**: Centralize **all** LLM calls through `generateTextService` or `generateObjectService`. * ✅ **DO**: Determine the appropriate `role` (`main`, `research`, `fallback`) in your core logic and pass it to the service. * ✅ **DO**: Pass the `session` object (received in the `context` parameter, especially from direct function wrappers) to the service call when in MCP context. * ✅ **DO**: Ensure API keys are correctly configured in `.env` (for CLI) or `.cursor/mcp.json` (for MCP). * ✅ **DO**: Ensure `.taskmasterconfig` exists and has valid provider/model IDs for the roles you intend to use (manage via `task-master models --setup`). * ✅ **DO**: Use `generateTextService` and implement robust manual JSON parsing (with Zod validation *after* parsing) when structured output is needed, as `generateObjectService` has shown unreliability with some providers/schemas. * ❌ **DON'T**: Import or call anything from the old `ai-services.js`, `ai-client-factory.js`, or `ai-client-utils.js` files. * ❌ **DON'T**: Initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic (`task-manager/`) or MCP direct functions. * ❌ **DON'T**: Fetch AI-specific parameters (model ID, max tokens, temp) using `config-manager.js` getters *for the AI call*. Pass the `role` instead. * ❌ **DON'T**: Implement fallback or retry logic outside `ai-services-unified.js`. * ❌ **DON'T**: Handle API key resolution outside the service layer (it uses `utils.js` internally). * ⚠️ **generateObjectService Caution**: Be aware of potential reliability issues with `generateObjectService` across different providers and complex schemas. Prefer `generateTextService` + manual parsing as a more robust alternative for structured data needs.