@mseep/ai-tech-app-agent 1.0.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.
Files changed (67) hide show
  1. package/.env +24 -0
  2. package/.env.example +24 -0
  3. package/Jenkinsfile +210 -0
  4. package/MCP-SERVER-GUIDE.md +405 -0
  5. package/README.MD +450 -0
  6. package/dist/config/app.config.d.ts +65 -0
  7. package/dist/config/app.config.d.ts.map +1 -0
  8. package/dist/config/app.config.js +94 -0
  9. package/dist/config/app.config.js.map +1 -0
  10. package/dist/config/llm.config.d.ts +63 -0
  11. package/dist/config/llm.config.d.ts.map +1 -0
  12. package/dist/config/llm.config.js +158 -0
  13. package/dist/config/llm.config.js.map +1 -0
  14. package/dist/config/mcp.config.d.ts +175 -0
  15. package/dist/config/mcp.config.d.ts.map +1 -0
  16. package/dist/config/mcp.config.js +215 -0
  17. package/dist/config/mcp.config.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +175 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/llm/llamaClient.d.ts +14 -0
  23. package/dist/llm/llamaClient.d.ts.map +1 -0
  24. package/dist/llm/llamaClient.js +136 -0
  25. package/dist/llm/llamaClient.js.map +1 -0
  26. package/dist/mcp/mcpClient.d.ts +132 -0
  27. package/dist/mcp/mcpClient.d.ts.map +1 -0
  28. package/dist/mcp/mcpClient.js +784 -0
  29. package/dist/mcp/mcpClient.js.map +1 -0
  30. package/dist/models/testSpec.d.ts +78 -0
  31. package/dist/models/testSpec.d.ts.map +1 -0
  32. package/dist/models/testSpec.js +3 -0
  33. package/dist/models/testSpec.js.map +1 -0
  34. package/dist/orchestrator/aiTestRunner.d.ts +18 -0
  35. package/dist/orchestrator/aiTestRunner.d.ts.map +1 -0
  36. package/dist/orchestrator/aiTestRunner.js +247 -0
  37. package/dist/orchestrator/aiTestRunner.js.map +1 -0
  38. package/dist/utils/logger.d.ts +4 -0
  39. package/dist/utils/logger.d.ts.map +1 -0
  40. package/dist/utils/logger.js +49 -0
  41. package/dist/utils/logger.js.map +1 -0
  42. package/dist/utils/promptBuilder.d.ts +62 -0
  43. package/dist/utils/promptBuilder.d.ts.map +1 -0
  44. package/dist/utils/promptBuilder.js +333 -0
  45. package/dist/utils/promptBuilder.js.map +1 -0
  46. package/knowledge/app-knowledge.txt +100 -0
  47. package/logs/combined.log +486 -0
  48. package/logs/error.log +50 -0
  49. package/package.json +62 -0
  50. package/reports/screenshots/screenshot_1764535110518.png +0 -0
  51. package/reports/test-report.json +106 -0
  52. package/scripts/check-mcp-server.sh +100 -0
  53. package/scripts/extract-pom-knowledge.js +222 -0
  54. package/scripts/pre-test-setup.js +262 -0
  55. package/scripts/start-mcp-server.sh +76 -0
  56. package/src/config/app.config.ts +175 -0
  57. package/src/config/llm.config.ts +220 -0
  58. package/src/config/mcp.config.ts +291 -0
  59. package/src/index.ts +161 -0
  60. package/src/llm/llamaClient.ts +159 -0
  61. package/src/mcp/mcpClient.ts +878 -0
  62. package/src/models/testSpec.ts +85 -0
  63. package/src/orchestrator/aiTestRunner.ts +286 -0
  64. package/src/utils/logger.ts +59 -0
  65. package/src/utils/promptBuilder.ts +384 -0
  66. package/tests/nlp-specs/login-flow.yaml +31 -0
  67. package/tsconfig.json +31 -0
@@ -0,0 +1,159 @@
1
+ import axios, { AxiosInstance } from 'axios';
2
+ import dotenv from 'dotenv';
3
+ import logger from '../utils/logger';
4
+ import { ActionPlan } from '../models/testSpec';
5
+
6
+ dotenv.config();
7
+
8
+ export class LlamaClient {
9
+ private client: AxiosInstance;
10
+ private model: string;
11
+ private temperature: number;
12
+ private maxTokens: number;
13
+
14
+ constructor() {
15
+ const baseURL = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
16
+ this.model = process.env.LLM_MODEL || 'llama3.2:3b';
17
+ this.temperature = parseFloat(process.env.LLM_TEMPERATURE || '0.1');
18
+ this.maxTokens = parseInt(process.env.LLM_MAX_TOKENS || '2000');
19
+
20
+ this.client = axios.create({
21
+ baseURL,
22
+ timeout: 60000,
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ });
27
+
28
+ logger.info(`LlamaClient initialized with model: ${this.model}`);
29
+ }
30
+
31
+ async generateActionPlan(
32
+ stepText: string,
33
+ uiContext: string,
34
+ appKnowledge?: string
35
+ ): Promise<ActionPlan> {
36
+ const prompt = this.buildPrompt(stepText, uiContext, appKnowledge);
37
+
38
+ try {
39
+ logger.debug(`Sending prompt to LLM for step: "${stepText}"`);
40
+
41
+ const response = await this.client.post('/api/generate', {
42
+ model: this.model,
43
+ prompt,
44
+ stream: false,
45
+ options: {
46
+ temperature: this.temperature,
47
+ num_predict: this.maxTokens,
48
+ },
49
+ format: 'json', // Request JSON output
50
+ });
51
+
52
+ const rawResponse = response.data.response;
53
+ logger.debug(`LLM raw response: ${rawResponse}`);
54
+
55
+ // Parse the JSON response
56
+ const actionPlan = this.parseActionPlan(rawResponse);
57
+ logger.info(`Generated ${actionPlan.actions.length} actions for step`);
58
+
59
+ return actionPlan;
60
+ } catch (error: any) {
61
+ logger.error(`Error generating action plan: ${error.message}`);
62
+ throw new Error(`LLM generation failed: ${error.message}`);
63
+ }
64
+ }
65
+
66
+ private buildPrompt(
67
+ stepText: string,
68
+ uiContext: string,
69
+ appKnowledge?: string
70
+ ): string {
71
+ return `You are an expert mobile test automation agent. Your task is to generate precise Appium actions to accomplish a test step.
72
+
73
+ **App Context:**
74
+ ${appKnowledge || 'A mobile application with standard Android/iOS UI patterns.'}
75
+
76
+ **Current UI State:**
77
+ ${uiContext}
78
+
79
+ **Test Step to Execute:**
80
+ "${stepText}"
81
+
82
+ **Instructions:**
83
+ 1. Analyze the current UI state carefully
84
+ 2. Identify the most reliable element selectors (prefer text, accessibility-id, or resource-id over XPath)
85
+ 3. Generate a sequence of actions to accomplish the test step
86
+ 4. Minimize screenshot-based coordinate selection - use it only as last resort
87
+ 5. Ensure actions are reliable across different device sizes
88
+
89
+ **Output Format (JSON only, no markdown):**
90
+ {
91
+ "actions": [
92
+ {
93
+ "type": "tap|type|scroll|swipe|wait|assert",
94
+ "selector": {
95
+ "strategy": "text|id|accessibility-id|xpath|class",
96
+ "value": "selector_value",
97
+ "index": 0
98
+ },
99
+ "value": "text_to_type (only for type action)",
100
+ "direction": "up|down|left|right (only for scroll/swipe)",
101
+ "assertionType": "exists|visible|text|enabled (only for assert)",
102
+ "expectedValue": "expected_value (only for assert)"
103
+ }
104
+ ],
105
+ "reasoning": "Brief explanation of the action sequence"
106
+ }
107
+
108
+ Generate the JSON action plan now:`;
109
+ }
110
+
111
+ private parseActionPlan(rawResponse: string): ActionPlan {
112
+ try {
113
+ // Remove any markdown code blocks if present
114
+ let cleanedResponse = rawResponse
115
+ .replace(/```json\n?/g, '')
116
+ .replace(/```\n?/g, '')
117
+ .trim();
118
+
119
+ const parsed = JSON.parse(cleanedResponse);
120
+
121
+ // Validate the structure
122
+ if (!parsed.actions || !Array.isArray(parsed.actions)) {
123
+ throw new Error('Invalid action plan structure: missing actions array');
124
+ }
125
+
126
+ return parsed as ActionPlan;
127
+ } catch (error: any) {
128
+ logger.error(`Failed to parse action plan: ${error.message}`);
129
+ logger.error(`Raw response: ${rawResponse}`);
130
+
131
+ // Return a fallback empty action plan
132
+ return {
133
+ actions: [],
134
+ reasoning: `Parsing failed: ${error.message}`,
135
+ };
136
+ }
137
+ }
138
+
139
+ async healthCheck(): Promise<boolean> {
140
+ try {
141
+ const response = await this.client.get('/api/tags');
142
+ const models = response.data.models || [];
143
+ const modelExists = models.some((m: any) => m.name === this.model);
144
+
145
+ if (!modelExists) {
146
+ logger.warn(`Model ${this.model} not found in Ollama. Available models: ${models.map((m: any) => m.name).join(', ')}`);
147
+ return false;
148
+ }
149
+
150
+ logger.info('LLM health check passed');
151
+ return true;
152
+ } catch (error: any) {
153
+ logger.error(`LLM health check failed: ${error.message}`);
154
+ return false;
155
+ }
156
+ }
157
+ }
158
+
159
+ export default LlamaClient;