@vfarcic/dot-ai 0.104.0 → 0.106.0
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 +6 -1
- package/dist/core/ai-provider-factory.d.ts +90 -0
- package/dist/core/ai-provider-factory.d.ts.map +1 -0
- package/dist/core/ai-provider-factory.js +187 -0
- package/dist/core/ai-provider.interface.d.ts +208 -0
- package/dist/core/ai-provider.interface.d.ts.map +1 -0
- package/dist/core/ai-provider.interface.js +14 -0
- package/dist/core/capabilities.d.ts +3 -3
- package/dist/core/capabilities.d.ts.map +1 -1
- package/dist/core/capabilities.js +4 -4
- package/dist/core/capability-scan-workflow.d.ts.map +1 -1
- package/dist/core/capability-scan-workflow.js +29 -14
- package/dist/core/doc-testing-session.d.ts +1 -1
- package/dist/core/doc-testing-session.js +1 -1
- package/dist/core/error-handling.js +2 -2
- package/dist/core/index.d.ts +4 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +11 -22
- package/dist/core/platform-operations.d.ts +9 -15
- package/dist/core/platform-operations.d.ts.map +1 -1
- package/dist/core/platform-operations.js +28 -49
- package/dist/core/platform-utils.d.ts +16 -0
- package/dist/core/platform-utils.d.ts.map +1 -0
- package/dist/core/platform-utils.js +68 -0
- package/dist/core/providers/anthropic-provider.d.ts +44 -0
- package/dist/core/providers/anthropic-provider.d.ts.map +1 -0
- package/dist/core/providers/anthropic-provider.js +281 -0
- package/dist/core/providers/provider-debug-utils.d.ts +27 -0
- package/dist/core/providers/provider-debug-utils.d.ts.map +1 -0
- package/dist/core/providers/provider-debug-utils.js +122 -0
- package/dist/core/providers/vercel-provider.d.ts +47 -0
- package/dist/core/providers/vercel-provider.d.ts.map +1 -0
- package/dist/core/providers/vercel-provider.js +152 -0
- package/dist/core/schema.d.ts +4 -7
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +13 -11
- package/dist/core/unified-creation-session.d.ts.map +1 -1
- package/dist/core/unified-creation-session.js +13 -14
- package/dist/interfaces/mcp.d.ts +1 -1
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +29 -8
- package/dist/interfaces/rest-api.js +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/tools/answer-question.d.ts.map +1 -1
- package/dist/tools/answer-question.js +8 -10
- package/dist/tools/build-platform.js +3 -3
- package/dist/tools/generate-manifests.d.ts.map +1 -1
- package/dist/tools/generate-manifests.js +7 -8
- package/dist/tools/organizational-data.d.ts.map +1 -1
- package/dist/tools/organizational-data.js +3 -2
- package/dist/tools/platform/discover-operations.tool.d.ts +35 -0
- package/dist/tools/platform/discover-operations.tool.d.ts.map +1 -0
- package/dist/tools/platform/discover-operations.tool.js +88 -0
- package/dist/tools/recommend.d.ts.map +1 -1
- package/dist/tools/recommend.js +50 -30
- package/dist/tools/remediate.d.ts.map +1 -1
- package/dist/tools/remediate.js +23 -39
- package/dist/tools/version.d.ts +3 -2
- package/dist/tools/version.d.ts.map +1 -1
- package/dist/tools/version.js +35 -23
- package/package.json +5 -2
- package/prompts/{parse-script-operations.md → platform-operations-parse-script-help.md} +4 -8
- package/prompts/question-generation.md +31 -3
- package/dist/core/claude.d.ts +0 -88
- package/dist/core/claude.d.ts.map +0 -1
- package/dist/core/claude.js +0 -414
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic AI Provider Implementation
|
|
4
|
+
*
|
|
5
|
+
* Implements AIProvider interface using Anthropic SDK directly.
|
|
6
|
+
* Supports streaming for long operations and debug logging.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AnthropicProvider = void 0;
|
|
13
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
14
|
+
const provider_debug_utils_1 = require("./provider-debug-utils");
|
|
15
|
+
class AnthropicProvider {
|
|
16
|
+
client;
|
|
17
|
+
apiKey;
|
|
18
|
+
model;
|
|
19
|
+
debugMode;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.apiKey = config.apiKey;
|
|
22
|
+
this.model = config.model || this.getDefaultModel();
|
|
23
|
+
this.debugMode = config.debugMode ?? (process.env.DEBUG_DOT_AI === 'true');
|
|
24
|
+
this.validateApiKey();
|
|
25
|
+
this.client = new sdk_1.default({
|
|
26
|
+
apiKey: this.apiKey,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
validateApiKey() {
|
|
30
|
+
if (!this.apiKey) {
|
|
31
|
+
throw new Error('API key is required for Anthropic provider');
|
|
32
|
+
}
|
|
33
|
+
if (this.apiKey.length === 0) {
|
|
34
|
+
throw new Error('Invalid API key: API key cannot be empty');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
getProviderType() {
|
|
38
|
+
return 'anthropic';
|
|
39
|
+
}
|
|
40
|
+
getDefaultModel() {
|
|
41
|
+
return 'claude-sonnet-4-5-20250929';
|
|
42
|
+
}
|
|
43
|
+
isInitialized() {
|
|
44
|
+
return this.client !== undefined;
|
|
45
|
+
}
|
|
46
|
+
async sendMessage(message, operation = 'generic') {
|
|
47
|
+
if (!this.client) {
|
|
48
|
+
throw new Error('Anthropic client not initialized');
|
|
49
|
+
}
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
try {
|
|
52
|
+
// Make real API call to Anthropic with streaming
|
|
53
|
+
const stream = await this.client.messages.create({
|
|
54
|
+
model: this.model,
|
|
55
|
+
max_tokens: 64000,
|
|
56
|
+
messages: [{ role: 'user', content: message }],
|
|
57
|
+
stream: true // Enable streaming by default to support long operations (>10 minutes)
|
|
58
|
+
});
|
|
59
|
+
let content = '';
|
|
60
|
+
let input_tokens = 0;
|
|
61
|
+
let output_tokens = 0;
|
|
62
|
+
for await (const chunk of stream) {
|
|
63
|
+
if (chunk.type === 'message_start') {
|
|
64
|
+
input_tokens = chunk.message.usage.input_tokens;
|
|
65
|
+
}
|
|
66
|
+
else if (chunk.type === 'content_block_delta') {
|
|
67
|
+
if (chunk.delta.type === 'text_delta') {
|
|
68
|
+
content += chunk.delta.text;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (chunk.type === 'message_delta') {
|
|
72
|
+
output_tokens = chunk.usage.output_tokens;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const response = {
|
|
76
|
+
content,
|
|
77
|
+
usage: {
|
|
78
|
+
input_tokens,
|
|
79
|
+
output_tokens
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const durationMs = Date.now() - startTime;
|
|
83
|
+
// Debug log the interaction if enabled
|
|
84
|
+
if (this.debugMode) {
|
|
85
|
+
const debugId = (0, provider_debug_utils_1.generateDebugId)(operation);
|
|
86
|
+
(0, provider_debug_utils_1.debugLogInteraction)(debugId, message, response, operation, this.getProviderType(), this.model, this.debugMode);
|
|
87
|
+
(0, provider_debug_utils_1.logMetrics)(operation, this.getProviderType(), response.usage, durationMs, this.debugMode);
|
|
88
|
+
}
|
|
89
|
+
return response;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw new Error(`Anthropic API error: ${error}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Agentic tool loop implementation
|
|
97
|
+
*
|
|
98
|
+
* NOTE: This method is currently NOT USED in the codebase (as of PRD #136 completion).
|
|
99
|
+
*
|
|
100
|
+
* Analysis showed that SDK-based tool loops and JSON-based agentic loops are functionally
|
|
101
|
+
* equivalent - both allow AI to decide which tools to call and when to stop. The JSON-based
|
|
102
|
+
* approach we already use provides the same capabilities without the token overhead of
|
|
103
|
+
* tool schemas in every request.
|
|
104
|
+
*
|
|
105
|
+
* This implementation is kept for potential future use cases where SDK-managed tool loops
|
|
106
|
+
* might provide advantages (e.g., better provider-specific optimizations, simpler code for
|
|
107
|
+
* highly exploratory workflows).
|
|
108
|
+
*
|
|
109
|
+
* ONLY IMPLEMENTED IN ANTHROPIC PROVIDER - VercelAIProvider does not implement this method
|
|
110
|
+
* as it's not needed for current workflows. If you need toolLoop for other providers, you'll
|
|
111
|
+
* need to implement it there as well.
|
|
112
|
+
*
|
|
113
|
+
* See PRD #136 for full architecture analysis and decision rationale.
|
|
114
|
+
*/
|
|
115
|
+
async toolLoop(config) {
|
|
116
|
+
if (!this.client) {
|
|
117
|
+
throw new Error('Anthropic client not initialized');
|
|
118
|
+
}
|
|
119
|
+
const startTime = Date.now();
|
|
120
|
+
// Convert AITool[] to Anthropic Tool format
|
|
121
|
+
const tools = config.tools.map(t => ({
|
|
122
|
+
name: t.name,
|
|
123
|
+
description: t.description,
|
|
124
|
+
input_schema: t.inputSchema
|
|
125
|
+
}));
|
|
126
|
+
// Initialize conversation history
|
|
127
|
+
const initialContent = config.systemPrompt + '\n\n' + config.userMessage;
|
|
128
|
+
const conversationHistory = [
|
|
129
|
+
{
|
|
130
|
+
role: 'user',
|
|
131
|
+
content: initialContent
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
let iterations = 0;
|
|
135
|
+
const toolCallsExecuted = [];
|
|
136
|
+
const totalTokens = { input: 0, output: 0 };
|
|
137
|
+
const maxIterations = config.maxIterations || 20;
|
|
138
|
+
try {
|
|
139
|
+
while (iterations < maxIterations) {
|
|
140
|
+
iterations++;
|
|
141
|
+
// Call Anthropic API with tools
|
|
142
|
+
const response = await this.client.messages.create({
|
|
143
|
+
model: this.model,
|
|
144
|
+
max_tokens: 4096,
|
|
145
|
+
messages: conversationHistory,
|
|
146
|
+
tools: tools
|
|
147
|
+
});
|
|
148
|
+
// Track token usage
|
|
149
|
+
totalTokens.input += response.usage.input_tokens;
|
|
150
|
+
totalTokens.output += response.usage.output_tokens;
|
|
151
|
+
// Check if AI wants to use tools
|
|
152
|
+
const toolUses = response.content.filter((c) => c.type === 'tool_use');
|
|
153
|
+
if (toolUses.length === 0) {
|
|
154
|
+
// AI is done - extract final text message
|
|
155
|
+
const textContent = response.content.find((c) => c.type === 'text');
|
|
156
|
+
const result = {
|
|
157
|
+
finalMessage: textContent?.text || '',
|
|
158
|
+
iterations,
|
|
159
|
+
toolCallsExecuted,
|
|
160
|
+
totalTokens
|
|
161
|
+
};
|
|
162
|
+
// Log metrics for the entire tool loop
|
|
163
|
+
const durationMs = Date.now() - startTime;
|
|
164
|
+
if (this.debugMode) {
|
|
165
|
+
const operation = config.operation || 'tool-loop';
|
|
166
|
+
(0, provider_debug_utils_1.logMetrics)(operation, this.getProviderType(), {
|
|
167
|
+
input_tokens: totalTokens.input,
|
|
168
|
+
output_tokens: totalTokens.output
|
|
169
|
+
}, durationMs, this.debugMode);
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
// Execute all requested tools
|
|
174
|
+
const toolResults = [];
|
|
175
|
+
for (const toolUse of toolUses) {
|
|
176
|
+
try {
|
|
177
|
+
const result = await config.toolExecutor(toolUse.name, toolUse.input);
|
|
178
|
+
toolCallsExecuted.push({
|
|
179
|
+
tool: toolUse.name,
|
|
180
|
+
input: toolUse.input,
|
|
181
|
+
output: result
|
|
182
|
+
});
|
|
183
|
+
toolResults.push({
|
|
184
|
+
type: 'tool_result',
|
|
185
|
+
tool_use_id: toolUse.id,
|
|
186
|
+
content: JSON.stringify(result)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
// Feed error back to AI as tool result
|
|
191
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
192
|
+
toolResults.push({
|
|
193
|
+
type: 'tool_result',
|
|
194
|
+
tool_use_id: toolUse.id,
|
|
195
|
+
content: JSON.stringify({ error: errorMessage }),
|
|
196
|
+
is_error: true
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Add AI response and tool results to conversation history
|
|
201
|
+
conversationHistory.push({ role: 'assistant', content: response.content }, { role: 'user', content: toolResults });
|
|
202
|
+
// Invoke iteration callback if provided
|
|
203
|
+
if (config.onIteration) {
|
|
204
|
+
config.onIteration(iterations, toolCallsExecuted);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
throw new Error(`Tool loop exceeded max iterations (${maxIterations})`);
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
if (error instanceof Error && error.message.includes('exceeded max iterations')) {
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
throw new Error(`Anthropic tool loop error: ${error}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async sendMessageWithTools(message, tools, toolExecutor, operation = 'tool-call') {
|
|
217
|
+
if (!this.client) {
|
|
218
|
+
throw new Error('Anthropic client not initialized');
|
|
219
|
+
}
|
|
220
|
+
// Convert AITool[] to Anthropic Tool format
|
|
221
|
+
const anthropicTools = tools.map(t => ({
|
|
222
|
+
name: t.name,
|
|
223
|
+
description: t.description,
|
|
224
|
+
input_schema: t.inputSchema
|
|
225
|
+
}));
|
|
226
|
+
try {
|
|
227
|
+
// Single API call with tools
|
|
228
|
+
const response = await this.client.messages.create({
|
|
229
|
+
model: this.model,
|
|
230
|
+
max_tokens: 4096,
|
|
231
|
+
messages: [{ role: 'user', content: message }],
|
|
232
|
+
tools: anthropicTools
|
|
233
|
+
});
|
|
234
|
+
const toolCalls = [];
|
|
235
|
+
let textContent = '';
|
|
236
|
+
// Process response content
|
|
237
|
+
for (const block of response.content) {
|
|
238
|
+
if (block.type === 'text') {
|
|
239
|
+
textContent += block.text;
|
|
240
|
+
}
|
|
241
|
+
else if (block.type === 'tool_use') {
|
|
242
|
+
// Execute the tool
|
|
243
|
+
try {
|
|
244
|
+
const result = await toolExecutor(block.name, block.input);
|
|
245
|
+
toolCalls.push({
|
|
246
|
+
tool: block.name,
|
|
247
|
+
input: block.input,
|
|
248
|
+
output: result
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
253
|
+
toolCalls.push({
|
|
254
|
+
tool: block.name,
|
|
255
|
+
input: block.input,
|
|
256
|
+
error: errorMessage
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const aiResponse = {
|
|
262
|
+
content: textContent,
|
|
263
|
+
usage: {
|
|
264
|
+
input_tokens: response.usage.input_tokens,
|
|
265
|
+
output_tokens: response.usage.output_tokens
|
|
266
|
+
},
|
|
267
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined
|
|
268
|
+
};
|
|
269
|
+
// Debug log if enabled
|
|
270
|
+
if (this.debugMode) {
|
|
271
|
+
const debugId = (0, provider_debug_utils_1.generateDebugId)(operation);
|
|
272
|
+
(0, provider_debug_utils_1.debugLogInteraction)(debugId, message, aiResponse, operation, this.getProviderType(), this.model, this.debugMode);
|
|
273
|
+
}
|
|
274
|
+
return aiResponse;
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
throw new Error(`Anthropic tool call error: ${error}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
exports.AnthropicProvider = AnthropicProvider;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared debugging utilities for AI providers
|
|
3
|
+
*
|
|
4
|
+
* Common functions for logging metrics and debugging AI interactions
|
|
5
|
+
* when DEBUG_DOT_AI=true
|
|
6
|
+
*/
|
|
7
|
+
import { AIResponse } from '../ai-provider.interface';
|
|
8
|
+
/**
|
|
9
|
+
* Create debug directory if it doesn't exist
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureDebugDirectory(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Generate unique identifier for debug files with operation context
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateDebugId(operation: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Log metrics for token usage and execution time when DEBUG_DOT_AI=true
|
|
18
|
+
*/
|
|
19
|
+
export declare function logMetrics(operation: string, provider: string, usage: {
|
|
20
|
+
input_tokens: number;
|
|
21
|
+
output_tokens: number;
|
|
22
|
+
}, durationMs: number, debugMode: boolean): void;
|
|
23
|
+
/**
|
|
24
|
+
* Save AI interaction for debugging when DEBUG_DOT_AI=true
|
|
25
|
+
*/
|
|
26
|
+
export declare function debugLogInteraction(debugId: string, prompt: string, response: AIResponse, operation: string, provider: string, model: string, debugMode: boolean): void;
|
|
27
|
+
//# sourceMappingURL=provider-debug-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-debug-utils.d.ts","sourceRoot":"","sources":["../../../src/core/providers/provider-debug-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAM7C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EACtD,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,OAAO,GACjB,IAAI,CAoBN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,GACjB,IAAI,CAkCN"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared debugging utilities for AI providers
|
|
4
|
+
*
|
|
5
|
+
* Common functions for logging metrics and debugging AI interactions
|
|
6
|
+
* when DEBUG_DOT_AI=true
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.ensureDebugDirectory = ensureDebugDirectory;
|
|
43
|
+
exports.generateDebugId = generateDebugId;
|
|
44
|
+
exports.logMetrics = logMetrics;
|
|
45
|
+
exports.debugLogInteraction = debugLogInteraction;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const crypto = __importStar(require("crypto"));
|
|
49
|
+
/**
|
|
50
|
+
* Create debug directory if it doesn't exist
|
|
51
|
+
*/
|
|
52
|
+
function ensureDebugDirectory() {
|
|
53
|
+
const debugDir = path.join(process.cwd(), 'tmp', 'debug-ai');
|
|
54
|
+
if (!fs.existsSync(debugDir)) {
|
|
55
|
+
fs.mkdirSync(debugDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
return debugDir;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Generate unique identifier for debug files with operation context
|
|
61
|
+
*/
|
|
62
|
+
function generateDebugId(operation) {
|
|
63
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '').split('T');
|
|
64
|
+
const dateTime = timestamp[0] + 'T' + timestamp[1].substring(0, 6);
|
|
65
|
+
const randomHex = crypto.randomBytes(4).toString('hex');
|
|
66
|
+
return `${dateTime}_${randomHex}_${operation}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Log metrics for token usage and execution time when DEBUG_DOT_AI=true
|
|
70
|
+
*/
|
|
71
|
+
function logMetrics(operation, provider, usage, durationMs, debugMode) {
|
|
72
|
+
if (!debugMode)
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
const debugDir = ensureDebugDirectory();
|
|
76
|
+
const metricsFile = path.join(debugDir, 'metrics.jsonl');
|
|
77
|
+
const entry = JSON.stringify({
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
provider,
|
|
80
|
+
operation,
|
|
81
|
+
inputTokens: usage.input_tokens,
|
|
82
|
+
outputTokens: usage.output_tokens,
|
|
83
|
+
durationMs
|
|
84
|
+
}) + '\n';
|
|
85
|
+
fs.appendFileSync(metricsFile, entry);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.warn('Failed to log metrics:', error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Save AI interaction for debugging when DEBUG_DOT_AI=true
|
|
93
|
+
*/
|
|
94
|
+
function debugLogInteraction(debugId, prompt, response, operation, provider, model, debugMode) {
|
|
95
|
+
if (!debugMode)
|
|
96
|
+
return;
|
|
97
|
+
try {
|
|
98
|
+
const debugDir = ensureDebugDirectory();
|
|
99
|
+
// Save prompt with descriptive naming
|
|
100
|
+
const promptFile = path.join(debugDir, `${debugId}_prompt.md`);
|
|
101
|
+
fs.writeFileSync(promptFile, `# AI Prompt - ${operation}\n\nTimestamp: ${new Date().toISOString()}\nProvider: ${provider}\nModel: ${model}\nOperation: ${operation}\n\n---\n\n${prompt}`);
|
|
102
|
+
// Save response with matching naming
|
|
103
|
+
const responseFile = path.join(debugDir, `${debugId}_response.md`);
|
|
104
|
+
const responseContent = `# AI Response - ${operation}
|
|
105
|
+
|
|
106
|
+
Timestamp: ${new Date().toISOString()}
|
|
107
|
+
Provider: ${provider}
|
|
108
|
+
Model: ${model}
|
|
109
|
+
Operation: ${operation}
|
|
110
|
+
Input Tokens: ${response.usage.input_tokens}
|
|
111
|
+
Output Tokens: ${response.usage.output_tokens}
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
${response.content}`;
|
|
116
|
+
fs.writeFileSync(responseFile, responseContent);
|
|
117
|
+
console.log(`🐛 DEBUG: AI interaction logged to tmp/debug-ai/${debugId}_*.md`);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.warn('Failed to log AI debug interaction:', error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel AI Provider Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements AIProvider interface using Vercel AI SDK.
|
|
5
|
+
* Supports OpenAI and Google Gemini providers through unified interface.
|
|
6
|
+
*/
|
|
7
|
+
import { AIProvider, AIResponse, AIProviderConfig, AITool, ToolExecutor, ToolLoopConfig, AgenticResult } from '../ai-provider.interface';
|
|
8
|
+
export declare class VercelProvider implements AIProvider {
|
|
9
|
+
private providerType;
|
|
10
|
+
private model;
|
|
11
|
+
private apiKey;
|
|
12
|
+
private debugMode;
|
|
13
|
+
private modelInstance;
|
|
14
|
+
constructor(config: AIProviderConfig);
|
|
15
|
+
private validateConfiguration;
|
|
16
|
+
private initializeModel;
|
|
17
|
+
getProviderType(): string;
|
|
18
|
+
getDefaultModel(): string;
|
|
19
|
+
isInitialized(): boolean;
|
|
20
|
+
sendMessage(message: string, operation?: string): Promise<AIResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* Agentic tool loop - NOT IMPLEMENTED for Vercel provider
|
|
23
|
+
*
|
|
24
|
+
* This method is intentionally not implemented because:
|
|
25
|
+
* 1. toolLoop() is currently NOT USED anywhere in the codebase (see PRD #136)
|
|
26
|
+
* 2. JSON-based agentic loops already provide equivalent functionality
|
|
27
|
+
* 3. No current workflows require SDK-managed tool loops
|
|
28
|
+
*
|
|
29
|
+
* If future requirements necessitate toolLoop() for non-Anthropic providers,
|
|
30
|
+
* this would need to be implemented using Vercel AI SDK's tool calling API.
|
|
31
|
+
*
|
|
32
|
+
* See AnthropicProvider.toolLoop() and PRD #136 for implementation reference.
|
|
33
|
+
*/
|
|
34
|
+
toolLoop(_config: ToolLoopConfig): Promise<AgenticResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Single-shot tool calling - NOT IMPLEMENTED for Vercel provider
|
|
37
|
+
*
|
|
38
|
+
* Same reasoning as toolLoop(): not currently needed in codebase.
|
|
39
|
+
* JSON-based approach achieves same functionality without SDK overhead.
|
|
40
|
+
*
|
|
41
|
+
* See AnthropicProvider.sendMessageWithTools() for reference implementation.
|
|
42
|
+
*/
|
|
43
|
+
sendMessageWithTools(_message: string, _tools: AITool[], _toolExecutor: ToolExecutor, _operation?: string): Promise<AIResponse & {
|
|
44
|
+
toolCalls?: any[];
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=vercel-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-provider.d.ts","sourceRoot":"","sources":["../../../src/core/providers/vercel-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,MAAM,EACN,YAAY,EACZ,cAAc,EACd,aAAa,EACd,MAAM,0BAA0B,CAAC;AAclC,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,aAAa,CAAM;gBAEf,MAAM,EAAE,gBAAgB;IAUpC,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,eAAe;IAgCvB,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,MAAM;IAIzB,aAAa,IAAI,OAAO;IAIlB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuCtF;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAQ/D;;;;;;;OAOG;IACG,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,aAAa,EAAE,YAAY,EAC3B,UAAU,GAAE,MAAoB,GAC/B,OAAO,CAAC,UAAU,GAAG;QAAE,SAAS,CAAC,EAAE,GAAG,EAAE,CAAA;KAAE,CAAC;CAO/C"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Vercel AI Provider Implementation
|
|
4
|
+
*
|
|
5
|
+
* Implements AIProvider interface using Vercel AI SDK.
|
|
6
|
+
* Supports OpenAI and Google Gemini providers through unified interface.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.VercelProvider = void 0;
|
|
10
|
+
const ai_1 = require("ai");
|
|
11
|
+
const openai_1 = require("@ai-sdk/openai");
|
|
12
|
+
const google_1 = require("@ai-sdk/google");
|
|
13
|
+
const anthropic_1 = require("@ai-sdk/anthropic");
|
|
14
|
+
const provider_debug_utils_1 = require("./provider-debug-utils");
|
|
15
|
+
/**
|
|
16
|
+
* Provider-specific default models
|
|
17
|
+
*/
|
|
18
|
+
const PROVIDER_MODELS = {
|
|
19
|
+
openai: 'gpt-5',
|
|
20
|
+
google: 'gemini-2.5-pro',
|
|
21
|
+
anthropic: 'claude-sonnet-4-5-20250929'
|
|
22
|
+
};
|
|
23
|
+
class VercelProvider {
|
|
24
|
+
providerType;
|
|
25
|
+
model;
|
|
26
|
+
apiKey;
|
|
27
|
+
debugMode;
|
|
28
|
+
modelInstance; // Vercel AI SDK model instance
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.apiKey = config.apiKey;
|
|
31
|
+
this.providerType = config.provider;
|
|
32
|
+
this.model = config.model || this.getDefaultModel();
|
|
33
|
+
this.debugMode = config.debugMode ?? (process.env.DEBUG_DOT_AI === 'true');
|
|
34
|
+
this.validateConfiguration();
|
|
35
|
+
this.initializeModel();
|
|
36
|
+
}
|
|
37
|
+
validateConfiguration() {
|
|
38
|
+
if (!this.apiKey) {
|
|
39
|
+
throw new Error(`API key is required for ${this.providerType} provider`);
|
|
40
|
+
}
|
|
41
|
+
if (!['openai', 'google', 'anthropic'].includes(this.providerType)) {
|
|
42
|
+
throw new Error(`Unsupported provider: ${this.providerType}. Must be 'openai', 'google', or 'anthropic'`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
initializeModel() {
|
|
46
|
+
try {
|
|
47
|
+
switch (this.providerType) {
|
|
48
|
+
case 'openai': {
|
|
49
|
+
const provider = (0, openai_1.createOpenAI)({
|
|
50
|
+
apiKey: this.apiKey
|
|
51
|
+
});
|
|
52
|
+
this.modelInstance = provider(this.model);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 'google': {
|
|
56
|
+
const provider = (0, google_1.createGoogleGenerativeAI)({
|
|
57
|
+
apiKey: this.apiKey
|
|
58
|
+
});
|
|
59
|
+
this.modelInstance = provider(this.model);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'anthropic': {
|
|
63
|
+
const provider = (0, anthropic_1.createAnthropic)({
|
|
64
|
+
apiKey: this.apiKey
|
|
65
|
+
});
|
|
66
|
+
this.modelInstance = provider(this.model);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
throw new Error(`Cannot initialize model for provider: ${this.providerType}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
throw new Error(`Failed to initialize ${this.providerType} model: ${error}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
getProviderType() {
|
|
78
|
+
return this.providerType;
|
|
79
|
+
}
|
|
80
|
+
getDefaultModel() {
|
|
81
|
+
return PROVIDER_MODELS[this.providerType];
|
|
82
|
+
}
|
|
83
|
+
isInitialized() {
|
|
84
|
+
return this.modelInstance !== undefined;
|
|
85
|
+
}
|
|
86
|
+
async sendMessage(message, operation = 'generic') {
|
|
87
|
+
if (!this.isInitialized()) {
|
|
88
|
+
throw new Error(`${this.providerType} provider not initialized`);
|
|
89
|
+
}
|
|
90
|
+
const startTime = Date.now();
|
|
91
|
+
try {
|
|
92
|
+
// Use Vercel AI SDK generateText
|
|
93
|
+
// Note: maxTokens omitted - let SDK/provider use model-specific optimal defaults
|
|
94
|
+
const result = await (0, ai_1.generateText)({
|
|
95
|
+
model: this.modelInstance,
|
|
96
|
+
prompt: message,
|
|
97
|
+
});
|
|
98
|
+
const response = {
|
|
99
|
+
content: result.text,
|
|
100
|
+
usage: {
|
|
101
|
+
input_tokens: result.usage.inputTokens || 0,
|
|
102
|
+
output_tokens: result.usage.outputTokens || 0
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const durationMs = Date.now() - startTime;
|
|
106
|
+
// Debug log the interaction if enabled
|
|
107
|
+
if (this.debugMode) {
|
|
108
|
+
const debugId = (0, provider_debug_utils_1.generateDebugId)(operation);
|
|
109
|
+
(0, provider_debug_utils_1.debugLogInteraction)(debugId, message, response, operation, this.getProviderType(), this.model, this.debugMode);
|
|
110
|
+
(0, provider_debug_utils_1.logMetrics)(operation, this.getProviderType(), response.usage, durationMs, this.debugMode);
|
|
111
|
+
}
|
|
112
|
+
return response;
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new Error(`${this.providerType} API error: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Agentic tool loop - NOT IMPLEMENTED for Vercel provider
|
|
120
|
+
*
|
|
121
|
+
* This method is intentionally not implemented because:
|
|
122
|
+
* 1. toolLoop() is currently NOT USED anywhere in the codebase (see PRD #136)
|
|
123
|
+
* 2. JSON-based agentic loops already provide equivalent functionality
|
|
124
|
+
* 3. No current workflows require SDK-managed tool loops
|
|
125
|
+
*
|
|
126
|
+
* If future requirements necessitate toolLoop() for non-Anthropic providers,
|
|
127
|
+
* this would need to be implemented using Vercel AI SDK's tool calling API.
|
|
128
|
+
*
|
|
129
|
+
* See AnthropicProvider.toolLoop() and PRD #136 for implementation reference.
|
|
130
|
+
*/
|
|
131
|
+
async toolLoop(_config) {
|
|
132
|
+
if (!this.isInitialized()) {
|
|
133
|
+
throw new Error(`${this.providerType} provider not initialized`);
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`toolLoop() not implemented for ${this.providerType} provider. Use AnthropicProvider for tool-based workflows, or use JSON-based agentic loops (recommended).`);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Single-shot tool calling - NOT IMPLEMENTED for Vercel provider
|
|
139
|
+
*
|
|
140
|
+
* Same reasoning as toolLoop(): not currently needed in codebase.
|
|
141
|
+
* JSON-based approach achieves same functionality without SDK overhead.
|
|
142
|
+
*
|
|
143
|
+
* See AnthropicProvider.sendMessageWithTools() for reference implementation.
|
|
144
|
+
*/
|
|
145
|
+
async sendMessageWithTools(_message, _tools, _toolExecutor, _operation = 'tool-call') {
|
|
146
|
+
if (!this.isInitialized()) {
|
|
147
|
+
throw new Error(`${this.providerType} provider not initialized`);
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`sendMessageWithTools() not implemented for ${this.providerType} provider. Use AnthropicProvider for tool-based workflows, or use JSON-based approach (recommended).`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.VercelProvider = VercelProvider;
|
package/dist/core/schema.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Fetches structured OpenAPI schemas from Kubernetes API server and validates manifests
|
|
6
6
|
*/
|
|
7
7
|
import { ResourceExplanation } from './discovery';
|
|
8
|
+
import { AIProvider } from './ai-provider.interface';
|
|
8
9
|
export interface FieldConstraints {
|
|
9
10
|
minimum?: number;
|
|
10
11
|
maximum?: number;
|
|
@@ -97,9 +98,6 @@ export interface ResourceSolution {
|
|
|
97
98
|
patternInfluences?: PatternInfluence[];
|
|
98
99
|
usedPatterns?: boolean;
|
|
99
100
|
}
|
|
100
|
-
export interface AIRankingConfig {
|
|
101
|
-
claudeApiKey: string;
|
|
102
|
-
}
|
|
103
101
|
export interface ClusterOptions {
|
|
104
102
|
namespaces: string[];
|
|
105
103
|
storageClasses: string[];
|
|
@@ -151,12 +149,11 @@ export declare class ManifestValidator {
|
|
|
151
149
|
* ResourceRecommender determines which resources best meet user needs using AI
|
|
152
150
|
*/
|
|
153
151
|
export declare class ResourceRecommender {
|
|
154
|
-
private
|
|
155
|
-
private config;
|
|
152
|
+
private aiProvider;
|
|
156
153
|
private patternService?;
|
|
157
154
|
private capabilityService?;
|
|
158
155
|
private policyService?;
|
|
159
|
-
constructor(
|
|
156
|
+
constructor(aiProvider?: AIProvider);
|
|
160
157
|
/**
|
|
161
158
|
* Find the best resource solution(s) for user intent using two-phase analysis
|
|
162
159
|
*/
|
|
@@ -239,7 +236,7 @@ export declare class ResourceRecommender {
|
|
|
239
236
|
.replace('{patterns}', patternsContext);
|
|
240
237
|
|
|
241
238
|
|
|
242
|
-
const response = await this.
|
|
239
|
+
const response = await this.aiProvider.sendMessage(selectionPrompt, 'resource-selection');
|
|
243
240
|
|
|
244
241
|
try {
|
|
245
242
|
// Extract JSON from response with robust parsing
|