docs: Update documentation for new AI/config architecture and finalize cleanup
This commit updates all relevant documentation (READMEs, docs/*, .cursor/rules) to accurately reflect the finalized unified AI service architecture and the new configuration system (.taskmasterconfig + .env/mcp.json). It also includes the final code cleanup steps related to the refactoring.
Key Changes:
1. **Documentation Updates:**
* Revised `README.md`, `README-task-master.md`, `assets/scripts_README.md`, `docs/configuration.md`, and `docs/tutorial.md` to explain the new configuration split (.taskmasterconfig vs .env/mcp.json).
* Updated MCP configuration examples in READMEs and tutorials to only include API keys in the `env` block.
* Added/updated examples for using the `--research` flag in `docs/command-reference.md`, `docs/examples.md`, and `docs/tutorial.md`.
* Updated `.cursor/rules/ai_services.mdc`, `.cursor/rules/architecture.mdc`, `.cursor/rules/dev_workflow.mdc`, `.cursor/rules/mcp.mdc`, `.cursor/rules/taskmaster.mdc`, `.cursor/rules/utilities.mdc`, and `.cursor/rules/new_features.mdc` to align with the new architecture, removing references to old patterns/files.
* Removed internal rule links from user-facing rules (`taskmaster.mdc`, `dev_workflow.mdc`, `self_improve.mdc`).
* Deleted outdated example file `docs/ai-client-utils-example.md`.
2. **Final Code Refactor & Cleanup:**
* Corrected `update-task-by-id.js` by removing the last import from the old `ai-services.js`.
* Refactored `update-subtask-by-id.js` to correctly use the unified service and logger patterns.
* Removed the obsolete export block from `mcp-server/src/core/task-master-core.js`.
* Corrected logger implementation in `update-tasks.js` for CLI context.
* Updated API key mapping in `config-manager.js` and `ai-services-unified.js`.
3. **Configuration Files:**
* Updated API keys in `.cursor/mcp.json`, replacing `GROK_API_KEY` with `XAI_API_KEY`.
* Updated `.env.example` with current API key names.
* Added `azureOpenaiBaseUrl` to `.taskmasterconfig` example.
4. **Task Management:**
* Marked documentation subtask 61.10 as 'done'.
* Includes various other task content/status updates from the diff summary.
5. **Changeset:**
* Added `.changeset/cuddly-zebras-matter.md` for user-facing `expand`/`expand-all` improvements.
This commit concludes the major architectural refactoring (Task 61) and ensures the documentation accurately reflects the current system.
This commit is contained in:
@@ -5,114 +5,97 @@ globs: scripts/modules/ai-services-unified.js, scripts/modules/task-manager/*.js
|
||||
|
||||
# AI Services Layer Guidelines
|
||||
|
||||
This document outlines the architecture and usage patterns for interacting with Large Language Models (LLMs) via the Task Master's unified AI service layer. The goal is to centralize configuration, provider selection, API key management, fallback logic, and error handling.
|
||||
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`).
|
||||
* Defines the AI provider and model ID for different **roles** (`main`, `research`, `fallback`).
|
||||
* Stores parameters like `maxTokens` and `temperature` per role.
|
||||
* Managed via `task-master models --setup`.
|
||||
* [`config-manager.js`](mdc:scripts/modules/config-manager.js) provides getters (e.g., `getMainProvider()`, `getMainModelId()`, `getParametersForRole()`) to access these settings.
|
||||
* API keys are **NOT** stored here; they are resolved via `resolveEnvVariable` from `.env` or MCP session env. See [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc).
|
||||
* Relies on `data/supported-models.json` for model validation and metadata.
|
||||
* 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`, `streamTextService`, `generateObjectService`.
|
||||
* Exports primary interaction functions: `generateTextService`, `generateObjectService`. (Note: `streamTextService` exists but has known reliability issues with some providers/payloads).
|
||||
* Contains the core `_unifiedServiceRunner` logic.
|
||||
* Uses `config-manager.js` getters to determine the provider/model based on the requested `role`.
|
||||
* Implements the fallback sequence (main -> fallback -> research or variations).
|
||||
* Constructs the `messages` array (`[{ role: 'system', ... }, { role: 'user', ... }]`) required by the Vercel AI SDK.
|
||||
* Calls internal retry logic (`_attemptProviderCallWithRetries`).
|
||||
* Resolves API keys via `_resolveApiKey`.
|
||||
* Maps requests to the correct provider implementation via `PROVIDER_FUNCTIONS`.
|
||||
* 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`.
|
||||
|
||||
* **Provider Implementations (`src/ai-providers/*.js`):**
|
||||
* Contain provider-specific code (e.g., `src/ai-providers/anthropic.js`).
|
||||
* Import Vercel AI SDK provider adapters (`@ai-sdk/anthropic`, `@ai-sdk/perplexity`, etc.).
|
||||
* Wrap core Vercel AI SDK functions (`generateText`, `streamText`, `generateObject`).
|
||||
* Accept standard parameters (`apiKey`, `modelId`, `messages`, `maxTokens`, etc.).
|
||||
* Return results in the format expected by `_unifiedServiceRunner`.
|
||||
* Contain provider-specific wrappers around Vercel AI SDK functions (`generateText`, `generateObject`).
|
||||
|
||||
**Usage Pattern (from Core Logic like `task-manager`):**
|
||||
**Usage Pattern (from Core Logic like `task-manager/*.js`):**
|
||||
|
||||
1. **Choose Service:** Decide whether you need a full text response (`generateTextService`) or a stream (`streamTextService`).
|
||||
* ✅ **DO**: **Prefer `generateTextService`** for interactions that send large context payloads (e.g., stringified JSON) and **do not** require incremental display in the UI. This is currently more reliable, especially if Anthropic is the configured provider.
|
||||
* ⚠️ **CAUTION**: `streamTextService` may be unreliable with the Vercel SDK's Anthropic adapter when sending large user messages. Use with caution or stick to `generateTextService` for such cases until SDK improvements are confirmed.
|
||||
|
||||
2. **Import Service:** Import the chosen service function from `../ai-services-unified.js`.
|
||||
1. **Import Service:** Import `generateTextService` or `generateObjectService` from `../ai-services-unified.js`.
|
||||
```javascript
|
||||
// Preferred for updateSubtaskById, parsePRD, etc.
|
||||
// Preferred for most tasks (especially with complex JSON)
|
||||
import { generateTextService } from '../ai-services-unified.js';
|
||||
|
||||
// Use only if incremental display is implemented AND provider streaming is reliable
|
||||
// import { streamTextService } from '../ai-services-unified.js';
|
||||
// Use if structured output is reliable for the specific use case
|
||||
// import { generateObjectService } from '../ai-services-unified.js';
|
||||
```
|
||||
|
||||
3. **Prepare Parameters:** Construct the parameters object.
|
||||
* `role`: `'main'`, `'research'`, or `'fallback'`. Determines the initial provider/model attempt.
|
||||
* `session`: Pass the MCP `session` object if available (for API key resolution), otherwise `null` or omit.
|
||||
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`): `schema`, `objectName`.
|
||||
* (For `generateObjectService` only): `schema` (Zod schema), `objectName`.
|
||||
|
||||
4. **Call Service:** Use `await` to call the service function.
|
||||
3. **Call Service:** Use `await` to call the service function.
|
||||
```javascript
|
||||
// Example using generateTextService
|
||||
// Example using generateTextService (most common)
|
||||
try {
|
||||
const resultText = await generateTextService({
|
||||
role: 'main', // Or 'research'/'fallback'
|
||||
session: session, // Or null
|
||||
systemPrompt: "You are...",
|
||||
prompt: userMessageContent // Can include stringified JSON etc.
|
||||
});
|
||||
additionalInformation = resultText.trim();
|
||||
// ... process resultText ...
|
||||
} catch (error) {
|
||||
// Handle errors thrown if all providers/retries fail
|
||||
report(`AI service call failed: ${error.message}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Example using streamTextService (Use with caution for Anthropic/large payloads)
|
||||
try {
|
||||
const streamResult = await streamTextService({
|
||||
role: 'main',
|
||||
session: session,
|
||||
role: useResearch ? 'research' : 'main', // Determine role based on logic
|
||||
session: context.session, // Pass session from context object
|
||||
systemPrompt: "You are...",
|
||||
prompt: userMessageContent
|
||||
});
|
||||
|
||||
// Check if a stream was actually returned (might be null if overridden)
|
||||
if (streamResult.textStream) {
|
||||
for await (const chunk of streamResult.textStream) {
|
||||
additionalInformation += chunk;
|
||||
}
|
||||
additionalInformation = additionalInformation.trim();
|
||||
} else if (streamResult.text) {
|
||||
// Handle case where generateText was used internally (Anthropic override)
|
||||
// NOTE: This override logic is currently REMOVED as we prefer generateTextService directly
|
||||
additionalInformation = streamResult.text.trim();
|
||||
} else {
|
||||
additionalInformation = ''; // Should not happen
|
||||
}
|
||||
// ... process additionalInformation ...
|
||||
// Process the raw text response (e.g., parse JSON, use directly)
|
||||
// ...
|
||||
} catch (error) {
|
||||
report(`AI service call failed: ${error.message}`, '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;
|
||||
}
|
||||
```
|
||||
|
||||
5. **Handle Results/Errors:** Process the returned text/stream/object or handle errors thrown by the service layer.
|
||||
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 AI calls through `generateTextService` / `streamTextService`.
|
||||
* ✅ **DO**: Ensure `.taskmasterconfig` has valid provider names, model IDs, and parameters (`maxTokens` appropriate for the model).
|
||||
* ✅ **DO**: Ensure API keys are correctly configured in `.env` / `.cursor/mcp.json`.
|
||||
* ✅ **DO**: Pass the `session` object to the service call if available (for MCP calls).
|
||||
* ❌ **DON'T**: Call Vercel AI SDK functions (`streamText`, `generateText`) directly from `task-manager` or commands.
|
||||
* ✅ **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.
|
||||
* ⚠️ **Streaming Caution**: Be aware of potential reliability issues using `streamTextService` with Anthropic/large payloads via the SDK. Prefer `generateTextService` for these cases until proven otherwise.
|
||||
* ⚠️ **Debugging Imports**: If you get `"X is not defined"` errors related to service functions, check for internal errors within `ai-services-unified.js` (like incorrect import paths or syntax errors).
|
||||
* ❌ **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.
|
||||
|
||||
Reference in New Issue
Block a user