@vfarcic/dot-ai 0.159.0 → 0.161.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 CHANGED
@@ -87,7 +87,7 @@ Access curated prompts as native slash commands (`/dot-ai:prompt-name`) in your
87
87
  📖 [Learn more →](./docs/guides/mcp-prompts-guide.md)
88
88
 
89
89
  ### ⚡ AI Integration
90
- Works with Claude Code, Cursor, VS Code via Model Context Protocol. Supports multiple AI providers (Claude, GPT, Gemini) for flexibility and cost optimization.
90
+ Works with Claude Code, Cursor, VS Code via Model Context Protocol. Supports multiple AI providers (Claude, GPT, Gemini, Host LLM) for flexibility and cost optimization.
91
91
  📖 [AI Model Configuration](./docs/setup/mcp-setup.md#ai-model-configuration)
92
92
 
93
93
  ## Quick Start
@@ -1 +1 @@
1
- {"version":3,"file":"ai-provider-factory.d.ts","sourceRoot":"","sources":["../../src/core/ai-provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,UAAU,EACV,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AA2BjC;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU;IAuBnD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,aAAa,IAAI,UAAU;IA8ElC;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAMrD;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,IAAI,MAAM,EAAE;IAMxC;;;;;OAKG;IACH,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAGxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C"}
1
+ {"version":3,"file":"ai-provider-factory.d.ts","sourceRoot":"","sources":["../../src/core/ai-provider-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,UAAU,EACV,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AA4BjC;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU;IA2BnD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,aAAa,IAAI,UAAU;IAgFlC;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAMrD;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,IAAI,MAAM,EAAE;IAMxC;;;;;OAKG;IACH,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAGxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C"}
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.AIProviderFactory = void 0;
13
13
  exports.createAIProvider = createAIProvider;
14
14
  const vercel_provider_1 = require("./providers/vercel-provider");
15
+ const host_provider_1 = require("./providers/host-provider");
15
16
  const noop_provider_1 = require("./providers/noop-provider");
16
17
  const model_config_1 = require("./model-config");
17
18
  /**
@@ -53,6 +54,9 @@ class AIProviderFactory {
53
54
  * @throws Error if provider type is unsupported or configuration is invalid
54
55
  */
55
56
  static create(config) {
57
+ if (config.provider === model_config_1.CURRENT_MODELS.host) {
58
+ return new host_provider_1.HostProvider();
59
+ }
56
60
  // Validate configuration
57
61
  if (!config.apiKey) {
58
62
  throw new Error(`API key is required for ${config.provider} provider`);
@@ -101,6 +105,9 @@ class AIProviderFactory {
101
105
  // AWS credentials checked at runtime by AWS SDK (env vars, ~/.aws/credentials, IAM roles)
102
106
  apiKey = 'bedrock-uses-aws-credentials';
103
107
  }
108
+ else if (providerType === model_config_1.CURRENT_MODELS.host) {
109
+ return new host_provider_1.HostProvider();
110
+ }
104
111
  else {
105
112
  const apiKeyEnvVar = PROVIDER_ENV_KEYS[providerType];
106
113
  if (!apiKeyEnvVar) {
@@ -13,6 +13,7 @@ export declare const CURRENT_MODELS: {
13
13
  readonly kimi: "kimi-k2-0905-preview";
14
14
  readonly kimi_thinking: "kimi-k2-thinking";
15
15
  readonly xai: "grok-4";
16
+ readonly host: "host";
16
17
  readonly openrouter: "anthropic/claude-haiku-4.5";
17
18
  readonly custom: "gpt-5.1-codex";
18
19
  readonly amazon_bedrock: "global.anthropic.claude-sonnet-4-20250514-v1:0";
@@ -1 +1 @@
1
- {"version":3,"file":"model-config.d.ts","sourceRoot":"","sources":["../../src/core/model-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;CAYjB,CAAC;AAEX;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,OAAO,cAAc,GAAG,MAAM,CAE7E"}
1
+ {"version":3,"file":"model-config.d.ts","sourceRoot":"","sources":["../../src/core/model-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;CAajB,CAAC;AAEX;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,OAAO,cAAc,GAAG,MAAM,CAE7E"}
@@ -17,6 +17,7 @@ exports.CURRENT_MODELS = {
17
17
  kimi: 'kimi-k2-0905-preview', // PRD #237: Moonshot AI Kimi K2 - standard model with 256K context
18
18
  kimi_thinking: 'kimi-k2-thinking', // PRD #237: Moonshot AI Kimi K2 - extended thinking variant
19
19
  xai: 'grok-4',
20
+ host: 'host', // Delegates generation to the client via MCP Sampling
20
21
  openrouter: 'anthropic/claude-haiku-4.5', // PRD #194: OpenRouter default model (overridden by AI_MODEL env var)
21
22
  custom: 'gpt-5.1-codex', // PRD #194: Custom endpoint default model (overridden by AI_MODEL env var)
22
23
  amazon_bedrock: 'global.anthropic.claude-sonnet-4-20250514-v1:0' // PRD #175: Amazon Bedrock default model (overridden by AI_MODEL env var)
@@ -0,0 +1,43 @@
1
+ import { AIProvider, AIResponse, AgenticResult, ToolLoopConfig } from '../ai-provider.interface';
2
+ export interface SamplingMessage {
3
+ role: 'user' | 'assistant';
4
+ content: {
5
+ type: 'text';
6
+ text: string;
7
+ } | string;
8
+ }
9
+ export interface SamplingResult {
10
+ content: {
11
+ type: 'text';
12
+ text: string;
13
+ } | string;
14
+ }
15
+ export type SamplingHandler = (messages: SamplingMessage[], systemPrompt?: string, options?: any) => Promise<SamplingResult>;
16
+ export declare class HostProvider implements AIProvider {
17
+ private static samplingHandler?;
18
+ private debugMode;
19
+ constructor();
20
+ setSamplingHandler(handler: SamplingHandler): void;
21
+ isInitialized(): boolean;
22
+ getDefaultModel(): string;
23
+ getProviderType(): string;
24
+ getModelName(): string;
25
+ private logDebugIfEnabled;
26
+ sendMessage(message: string, operation?: string, evaluationContext?: {
27
+ user_intent?: string;
28
+ interaction_id?: string;
29
+ }): Promise<AIResponse>;
30
+ /**
31
+ * Execute a tool loop with the host model
32
+ *
33
+ * The tool loop relies on a specific JSON format embedded in markdown code blocks:
34
+ * ```json
35
+ * {
36
+ * "tool": "toolName",
37
+ * "arguments": { ... }
38
+ * }
39
+ * ```
40
+ */
41
+ toolLoop(config: ToolLoopConfig): Promise<AgenticResult>;
42
+ }
43
+ //# sourceMappingURL=host-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-provider.d.ts","sourceRoot":"","sources":["../../../src/core/providers/host-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACf,MAAM,0BAA0B,CAAC;AAkBlC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,MAAM,eAAe,GAAG,CAC5B,QAAQ,EAAE,eAAe,EAAE,EAC3B,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,GAAG,KACV,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,qBAAa,YAAa,YAAW,UAAU;IAC7C,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAkB;IACjD,OAAO,CAAC,SAAS,CAAU;;IAM3B,kBAAkB,CAAC,OAAO,EAAE,eAAe;IAI3C,aAAa,IAAI,OAAO;IAIxB,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM;IAItB,OAAO,CAAC,iBAAiB;IAwBnB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAkB,EAC7B,iBAAiB,CAAC,EAAE;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GACA,OAAO,CAAC,UAAU,CAAC;IA4HtB;;;;;;;;;;OAUG;IACG,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CA0K/D"}
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HostProvider = void 0;
37
+ const path = __importStar(require("path"));
38
+ const prompts_1 = require("../../tools/prompts");
39
+ const model_config_1 = require("../model-config");
40
+ const provider_debug_utils_1 = require("./provider-debug-utils");
41
+ const ai_tracing_1 = require("../tracing/ai-tracing");
42
+ const tool_utils_1 = require("./tool-utils");
43
+ class HostProvider {
44
+ static samplingHandler;
45
+ debugMode;
46
+ constructor() {
47
+ this.debugMode = process.env.DEBUG_DOT_AI === 'true';
48
+ }
49
+ setSamplingHandler(handler) {
50
+ HostProvider.samplingHandler = handler;
51
+ }
52
+ isInitialized() {
53
+ return !!HostProvider.samplingHandler;
54
+ }
55
+ getDefaultModel() {
56
+ return model_config_1.CURRENT_MODELS.host;
57
+ }
58
+ getProviderType() {
59
+ return model_config_1.CURRENT_MODELS.host;
60
+ }
61
+ getModelName() {
62
+ return model_config_1.CURRENT_MODELS.host;
63
+ }
64
+ logDebugIfEnabled(operation, prompt, response) {
65
+ if (!this.debugMode)
66
+ return null;
67
+ const debugId = (0, provider_debug_utils_1.generateDebugId)(operation);
68
+ (0, provider_debug_utils_1.debugLogInteraction)(debugId, prompt, response, operation, this.getProviderType(), this.getModelName(), this.debugMode);
69
+ return {
70
+ promptFile: `${debugId}_prompt.md`,
71
+ responseFile: `${debugId}_response.md`,
72
+ };
73
+ }
74
+ async sendMessage(message, operation = 'generic', evaluationContext) {
75
+ if (!HostProvider.samplingHandler) {
76
+ throw new Error('Host provider is not connected to MCP server');
77
+ }
78
+ return await (0, ai_tracing_1.withAITracing)({
79
+ provider: this.getProviderType(),
80
+ model: this.getModelName(),
81
+ operation: 'chat',
82
+ }, async () => {
83
+ const startTime = Date.now();
84
+ const messages = [
85
+ { role: 'user', content: { type: 'text', text: message } },
86
+ ];
87
+ try {
88
+ const result = await HostProvider.samplingHandler(messages, undefined, {
89
+ operation,
90
+ evaluationContext,
91
+ });
92
+ let content = '';
93
+ if (typeof result.content === 'object' && result.content.type === 'text') {
94
+ content = result.content.text;
95
+ }
96
+ else if (typeof result.content === 'string') {
97
+ content = result.content;
98
+ }
99
+ else {
100
+ content = JSON.stringify(result.content);
101
+ }
102
+ const response = {
103
+ content,
104
+ usage: {
105
+ input_tokens: 0,
106
+ output_tokens: 0,
107
+ },
108
+ };
109
+ const durationMs = Date.now() - startTime;
110
+ // Debug log the interaction if enabled
111
+ if (this.debugMode) {
112
+ this.logDebugIfEnabled(operation, message, response);
113
+ const evaluationMetrics = {
114
+ operation,
115
+ sdk: this.getProviderType(),
116
+ inputTokens: response.usage.input_tokens,
117
+ outputTokens: response.usage.output_tokens,
118
+ durationMs,
119
+ iterationCount: 1,
120
+ toolCallCount: 0,
121
+ status: 'completed',
122
+ completionReason: 'stop',
123
+ modelVersion: this.getModelName(),
124
+ test_scenario: operation,
125
+ ai_response_summary: response.content,
126
+ user_intent: evaluationContext?.user_intent || '',
127
+ interaction_id: evaluationContext?.interaction_id || '',
128
+ };
129
+ (0, provider_debug_utils_1.logEvaluationDataset)(evaluationMetrics, this.debugMode);
130
+ }
131
+ return response;
132
+ }
133
+ catch (error) {
134
+ const errorMessage = error instanceof Error ? error.message : String(error);
135
+ if (this.debugMode) {
136
+ const debugId = (0, provider_debug_utils_1.generateDebugId)(operation);
137
+ (0, provider_debug_utils_1.debugLogPromptOnly)(debugId, message, operation, this.getProviderType(), this.getModelName(), this.debugMode);
138
+ if (evaluationContext) {
139
+ const failureMetrics = {
140
+ operation,
141
+ user_intent: evaluationContext.user_intent || '',
142
+ ai_response_summary: `Error: ${errorMessage}`,
143
+ durationMs: Date.now() - startTime,
144
+ inputTokens: 0,
145
+ outputTokens: 0,
146
+ iterationCount: 0,
147
+ toolCallCount: 0,
148
+ status: 'failed',
149
+ completionReason: 'error',
150
+ sdk: this.getProviderType(),
151
+ modelVersion: this.getModelName(),
152
+ test_scenario: operation,
153
+ interaction_id: evaluationContext.interaction_id ||
154
+ (0, provider_debug_utils_1.generateDebugId)(operation),
155
+ failure_analysis: {
156
+ failure_type: 'error',
157
+ failure_reason: `Host API error: ${errorMessage}`,
158
+ time_to_failure: Date.now() - startTime,
159
+ },
160
+ };
161
+ (0, provider_debug_utils_1.logEvaluationDataset)(failureMetrics, this.debugMode);
162
+ }
163
+ }
164
+ throw new Error(`Host sampling error: ${errorMessage}`);
165
+ }
166
+ }, (response) => ({
167
+ inputTokens: response.usage.input_tokens,
168
+ outputTokens: response.usage.output_tokens,
169
+ }));
170
+ }
171
+ /**
172
+ * Execute a tool loop with the host model
173
+ *
174
+ * The tool loop relies on a specific JSON format embedded in markdown code blocks:
175
+ * ```json
176
+ * {
177
+ * "tool": "toolName",
178
+ * "arguments": { ... }
179
+ * }
180
+ * ```
181
+ */
182
+ async toolLoop(config) {
183
+ if (!HostProvider.samplingHandler) {
184
+ throw new Error('Host provider is not connected to MCP server');
185
+ }
186
+ return await (0, ai_tracing_1.withAITracing)({
187
+ provider: this.getProviderType(),
188
+ model: this.getModelName(),
189
+ operation: 'tool_loop',
190
+ }, async () => {
191
+ const maxIterations = config.maxIterations || 20;
192
+ const messages = [
193
+ { role: 'user', content: { type: 'text', text: config.userMessage } },
194
+ ];
195
+ // Construct system prompt with tool definitions
196
+ const promptPath = path.join(__dirname, '..', '..', '..', 'prompts', 'host-tools.md');
197
+ const promptTemplate = (0, prompts_1.loadPromptFile)(promptPath).content;
198
+ const toolDefinitions = (0, tool_utils_1.formatToolDefinitions)(config.tools);
199
+ const systemPrompt = config.systemPrompt +
200
+ '\n\n' +
201
+ promptTemplate.replace('{{TOOL_DEFINITIONS}}', toolDefinitions);
202
+ const toolCallsExecuted = [];
203
+ let iterations = 0;
204
+ while (iterations < maxIterations) {
205
+ iterations++;
206
+ try {
207
+ const result = await HostProvider.samplingHandler(messages, systemPrompt, {
208
+ operation: config.operation,
209
+ evaluationContext: config.evaluationContext,
210
+ interaction_id: config.interaction_id,
211
+ });
212
+ let content = '';
213
+ if (typeof result.content === 'object' && result.content.type === 'text') {
214
+ content = result.content.text;
215
+ }
216
+ else if (typeof result.content === 'string') {
217
+ content = result.content;
218
+ }
219
+ else {
220
+ content = JSON.stringify(result.content);
221
+ }
222
+ // Add assistant response to history
223
+ messages.push({
224
+ role: 'assistant',
225
+ content: { type: 'text', text: content },
226
+ });
227
+ // Check for tool calls
228
+ const toolCalls = (0, tool_utils_1.extractToolCalls)(content);
229
+ if (toolCalls.length > 0) {
230
+ for (const toolCall of toolCalls) {
231
+ try {
232
+ const toolName = toolCall.tool;
233
+ const toolArgs = toolCall.arguments || {};
234
+ // Validate tool exists
235
+ const toolExists = config.tools.some(t => t.name === toolName);
236
+ if (!toolExists) {
237
+ messages.push({
238
+ role: 'user',
239
+ content: {
240
+ type: 'text',
241
+ text: `Unknown tool '${toolName}'. Available tools: ${config.tools.map(t => t.name).join(', ')}`,
242
+ },
243
+ });
244
+ continue;
245
+ }
246
+ // Execute tool
247
+ const toolOutput = await config.toolExecutor(toolName, toolArgs);
248
+ toolCallsExecuted.push({
249
+ tool: toolName,
250
+ input: toolArgs,
251
+ output: toolOutput,
252
+ });
253
+ // Add tool result to history
254
+ messages.push({
255
+ role: 'user',
256
+ content: {
257
+ type: 'text',
258
+ text: (0, tool_utils_1.formatToolOutput)(toolName, toolOutput),
259
+ },
260
+ });
261
+ }
262
+ catch (executionError) {
263
+ messages.push({
264
+ role: 'user',
265
+ content: {
266
+ type: 'text',
267
+ text: `Error executing tool '${toolCall.tool}': ${executionError instanceof Error ? executionError.message : String(executionError)}`,
268
+ },
269
+ });
270
+ }
271
+ }
272
+ if (config.onIteration) {
273
+ try {
274
+ config.onIteration(iterations, toolCallsExecuted);
275
+ }
276
+ catch (error) {
277
+ // Ignore errors in callback
278
+ }
279
+ }
280
+ }
281
+ else {
282
+ // No tool call, assume final response
283
+ return {
284
+ finalMessage: content,
285
+ iterations,
286
+ toolCallsExecuted,
287
+ totalTokens: { input: 0, output: 0 },
288
+ };
289
+ }
290
+ }
291
+ catch (error) {
292
+ const message = error instanceof Error ? error.message : String(error);
293
+ throw new Error(`Host sampling error in tool loop: ${message}`);
294
+ }
295
+ }
296
+ const lastMessage = messages[messages.length - 1];
297
+ const lastContent = typeof lastMessage.content === 'string'
298
+ ? lastMessage.content
299
+ : (lastMessage.content?.text ?? '');
300
+ return {
301
+ finalMessage: lastContent,
302
+ iterations,
303
+ toolCallsExecuted,
304
+ totalTokens: { input: 0, output: 0 },
305
+ status: 'timeout',
306
+ completionReason: 'max_iterations',
307
+ };
308
+ }, (result) => ({
309
+ inputTokens: result.totalTokens.input,
310
+ outputTokens: result.totalTokens.output,
311
+ }));
312
+ }
313
+ }
314
+ exports.HostProvider = HostProvider;
@@ -0,0 +1,21 @@
1
+ import { AITool } from '../ai-provider.interface';
2
+ /**
3
+ * Formats tool definitions into a markdown string for system prompts.
4
+ * Used by providers that don't support native tool calling or need manual prompting.
5
+ */
6
+ export declare function formatToolDefinitions(tools: AITool[]): string;
7
+ /**
8
+ * Formats a tool execution result for inclusion in conversation history.
9
+ */
10
+ export declare function formatToolOutput(toolName: string, output: any): string;
11
+ /**
12
+ * Regex for extracting tool calls from markdown code blocks.
13
+ * Matches: ```json ... ``` and captures the content.
14
+ */
15
+ export declare const TOOL_CALL_REGEX: RegExp;
16
+ /**
17
+ * Extracts tool calls from a string containing markdown code blocks.
18
+ * Handles nested objects and malformed JSON gracefully.
19
+ */
20
+ export declare function extractToolCalls(content: string): any[];
21
+ //# sourceMappingURL=tool-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-utils.d.ts","sourceRoot":"","sources":["../../../src/core/providers/tool-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAO7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAgC,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,EAAE,CAuBvD"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TOOL_CALL_REGEX = void 0;
4
+ exports.formatToolDefinitions = formatToolDefinitions;
5
+ exports.formatToolOutput = formatToolOutput;
6
+ exports.extractToolCalls = extractToolCalls;
7
+ /**
8
+ * Formats tool definitions into a markdown string for system prompts.
9
+ * Used by providers that don't support native tool calling or need manual prompting.
10
+ */
11
+ function formatToolDefinitions(tools) {
12
+ let toolDefinitions = '';
13
+ for (const tool of tools) {
14
+ toolDefinitions += `### ${tool.name}\n${tool.description}\n`;
15
+ toolDefinitions += `Schema: ${JSON.stringify(tool.inputSchema)}\n\n`;
16
+ }
17
+ return toolDefinitions;
18
+ }
19
+ /**
20
+ * Formats a tool execution result for inclusion in conversation history.
21
+ */
22
+ function formatToolOutput(toolName, output) {
23
+ return `Tool '${toolName}' output:\n${JSON.stringify(output, null, 2)}`;
24
+ }
25
+ /**
26
+ * Regex for extracting tool calls from markdown code blocks.
27
+ * Matches: ```json ... ``` and captures the content.
28
+ */
29
+ exports.TOOL_CALL_REGEX = /```json\s*([\s\S]*?)\s*```/g;
30
+ /**
31
+ * Extracts tool calls from a string containing markdown code blocks.
32
+ * Handles nested objects and malformed JSON gracefully.
33
+ */
34
+ function extractToolCalls(content) {
35
+ const toolCalls = [];
36
+ const matches = [...content.matchAll(exports.TOOL_CALL_REGEX)];
37
+ for (const match of matches) {
38
+ try {
39
+ const jsonContent = match[1];
40
+ const parsed = JSON.parse(jsonContent);
41
+ if (Array.isArray(parsed)) {
42
+ for (const item of parsed) {
43
+ if (item && typeof item === 'object' && item.tool) {
44
+ toolCalls.push(item);
45
+ }
46
+ }
47
+ }
48
+ else if (parsed && typeof parsed === 'object' && parsed.tool) {
49
+ toolCalls.push(parsed);
50
+ }
51
+ }
52
+ catch (e) {
53
+ // Ignore parse errors
54
+ }
55
+ }
56
+ return toolCalls;
57
+ }
@@ -39,6 +39,8 @@ export declare class MCPServer {
39
39
  * Register prompts capability with McpServer
40
40
  */
41
41
  private registerPrompts;
42
+ private configureHostProvider;
43
+ private handleSamplingRequest;
42
44
  private generateRequestId;
43
45
  start(): Promise<void>;
44
46
  private startStdioTransport;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/interfaces/mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAkDtC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;CACxC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAAC,CAAkC;IACrD,OAAO,CAAC,aAAa,CAAC,CAAgC;IACtD,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe;IAsCjD;;OAEG;IACH,OAAO,CAAC,YAAY;IA2BpB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6HrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,iBAAiB;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBd,mBAAmB;YAMnB,kBAAkB;YAmHlB,gBAAgB;IAexB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,OAAO,IAAI,OAAO;CAGnB"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/interfaces/mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAkDtC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;CACxC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAAC,CAAkC;IACrD,OAAO,CAAC,aAAa,CAAC,CAAgC;IACtD,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe;IAyCjD;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6HrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,qBAAqB;YAgBf,qBAAqB;IAuBnC,OAAO,CAAC,iBAAiB;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBd,mBAAmB;YAMnB,kBAAkB;YAmHlB,gBAAgB;IAexB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,OAAO,IAAI,OAAO;CAGnB"}
@@ -52,6 +52,8 @@ class MCPServer {
52
52
  prompts: {},
53
53
  },
54
54
  });
55
+ // Configure HostProvider if active
56
+ this.configureHostProvider();
55
57
  this.logger.info('Initializing MCP Server', {
56
58
  name: config.name,
57
59
  version: config.version,
@@ -73,7 +75,10 @@ class MCPServer {
73
75
  return await (0, tracing_1.withToolTracing)(name, args, handler);
74
76
  };
75
77
  // Register traced handler with MCP server
76
- this.server.tool(name, description, inputSchema, tracedHandler);
78
+ this.server.registerTool(name, {
79
+ description,
80
+ inputSchema
81
+ }, tracedHandler);
77
82
  // Register traced handler with REST registry
78
83
  this.restRegistry.registerTool({
79
84
  name,
@@ -164,6 +169,39 @@ class MCPServer {
164
169
  endpoints: ['prompts/list', 'prompts/get'],
165
170
  });
166
171
  }
172
+ configureHostProvider() {
173
+ // Configure HostProvider if active
174
+ // We use capability detection (duck typing) to avoid strict class dependency
175
+ // and handle potential class loading issues
176
+ const aiProvider = this.dotAI.ai;
177
+ if (typeof aiProvider.setSamplingHandler === 'function') {
178
+ this.logger.info('Configuring Host AI Provider with Sampling capability');
179
+ aiProvider.setSamplingHandler(this.handleSamplingRequest.bind(this));
180
+ }
181
+ else {
182
+ this.logger.info('Using configured AI Provider', {
183
+ type: this.dotAI.ai.getProviderType ? this.dotAI.ai.getProviderType() : 'unknown'
184
+ });
185
+ }
186
+ }
187
+ async handleSamplingRequest(messages, systemPrompt, options) {
188
+ try {
189
+ if (!this.server.server.createMessage) {
190
+ throw new Error('Server does not support createMessage (sampling)');
191
+ }
192
+ return await this.server.server.createMessage({
193
+ messages,
194
+ systemPrompt,
195
+ includeContext: 'none',
196
+ maxTokens: options?.maxTokens || 4096,
197
+ ...options
198
+ });
199
+ }
200
+ catch (error) {
201
+ this.logger.error('Sampling request failed', error);
202
+ throw error;
203
+ }
204
+ }
167
205
  generateRequestId() {
168
206
  return `mcp_${Date.now()}_${++this.requestIdCounter}`;
169
207
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "0.159.0",
3
+ "version": "0.161.0",
4
4
  "description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
5
5
  "mcpName": "io.github.vfarcic/dot-ai",
6
6
  "main": "dist/index.js",
@@ -17,6 +17,7 @@
17
17
  "test:integration:teardown": "./tests/integration/infrastructure/teardown-cluster.sh",
18
18
  "test:integration:server": "KUBECONFIG=./kubeconfig-test.yaml PORT=3456 DOT_AI_SESSION_DIR=./tmp/sessions TRANSPORT_TYPE=http QDRANT_URL=http://localhost:6335 QDRANT_CAPABILITIES_COLLECTION=capabilities-policies ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY OPENAI_API_KEY=$OPENAI_API_KEY node dist/mcp/server.js",
19
19
  "test:integration": "./tests/integration/infrastructure/run-integration-tests.sh",
20
+ "test:unit": "vitest --config=vitest.unit.config.ts",
20
21
  "test:integration:watch": "vitest --config=vitest.integration.config.ts --test-timeout=1200000",
21
22
  "test:integration:sonnet": "AI_PROVIDER=anthropic DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
22
23
  "test:integration:opus": "AI_PROVIDER=anthropic_opus DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: host-tools
3
+ description: System prompt for host tools execution loop
4
+ category: core
5
+ ---
6
+ ## Available Tools
7
+
8
+ You have access to the following tools. To use a tool, output a JSON block with the format:
9
+ ```json
10
+ { "tool": "tool_name", "arguments": { ... } }
11
+ ```
12
+
13
+ {{TOOL_DEFINITIONS}}
14
+
15
+ When you have gathered enough information, provide your final answer without any tool calls.