auto-coder 0.1.215__py3-none-any.whl → 0.1.218__py3-none-any.whl
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.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/METADATA +2 -1
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/RECORD +24 -21
- autocoder/auto_coder.py +6 -2
- autocoder/auto_coder_rag.py +16 -0
- autocoder/chat_auto_coder.py +213 -98
- autocoder/command_args.py +5 -5
- autocoder/common/anything2img.py +196 -0
- autocoder/common/code_auto_generate.py +4 -1
- autocoder/common/code_auto_generate_diff.py +8 -2
- autocoder/common/code_auto_generate_editblock.py +8 -2
- autocoder/common/code_auto_generate_strict_diff.py +8 -2
- autocoder/common/command_completer.py +7 -0
- autocoder/common/mcp_hub.py +83 -7
- autocoder/common/mcp_server.py +249 -18
- autocoder/common/mcp_servers/__init__.py +0 -0
- autocoder/common/mcp_servers/mcp_server_perplexity.py +135 -0
- autocoder/common/mcp_tools.py +27 -379
- autocoder/index/index.py +1 -1
- autocoder/rag/types.py +77 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.215.dist-info → auto_coder-0.1.218.dist-info}/top_level.txt +0 -0
autocoder/common/mcp_tools.py
CHANGED
|
@@ -7,7 +7,8 @@ import re
|
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
8
|
from loguru import logger
|
|
9
9
|
import mcp.types as mcp_types
|
|
10
|
-
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
11
12
|
|
|
12
13
|
class McpToolCall(BaseModel):
|
|
13
14
|
server_name: str = Field(..., description="The name of the MCP server")
|
|
@@ -102,9 +103,11 @@ class McpExecutor:
|
|
|
102
103
|
info.append(server_info)
|
|
103
104
|
|
|
104
105
|
return "\n\n".join(info)
|
|
106
|
+
|
|
107
|
+
|
|
105
108
|
|
|
106
109
|
@byzerllm.prompt()
|
|
107
|
-
def mcp_prompt(self) -> str:
|
|
110
|
+
def mcp_prompt(self,query:str) -> str:
|
|
108
111
|
"""
|
|
109
112
|
TOOL USE
|
|
110
113
|
|
|
@@ -194,358 +197,19 @@ class McpExecutor:
|
|
|
194
197
|
When a server is connected, you can use the server's tools via the `use_mcp_tool` tool, and access the server's resources via the `access_mcp_resource` tool.
|
|
195
198
|
|
|
196
199
|
{{ connected_servers_info }}
|
|
197
|
-
|
|
198
|
-
## Creating an MCP Server
|
|
199
|
-
|
|
200
|
-
The user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`.
|
|
201
|
-
|
|
202
|
-
When creating MCP servers, it's important to understand that they operate in a non-interactive environment. The server cannot initiate OAuth flows, open browser windows, or prompt for user input during runtime. All credentials and authentication tokens must be provided upfront through environment variables in the MCP settings configuration. For example, Spotify's API uses OAuth to get a refresh token for the user, but the MCP server cannot initiate this flow. While you can walk the user through obtaining an application client ID and secret, you may have to create a separate one-time setup script (like get-refresh-token.js) that captures and logs the final piece of the puzzle: the user's refresh token (i.e. you might run the script using execute_command which would open a browser for authentication, and then log the refresh token so that you can see it in the command output for you to use in the MCP settings configuration).
|
|
203
|
-
|
|
204
|
-
Unless the user specifies otherwise, new MCP servers should be created in: ${await mcpHub.getMcpServersPath()}
|
|
205
|
-
|
|
206
|
-
### Example MCP Server
|
|
207
|
-
|
|
208
|
-
For example, if the user wanted to give you the ability to retrieve weather information, you could create an MCP server that uses the OpenWeather API to get weather information, add it to the MCP settings configuration file, and then notice that you now have access to new tools and resources in the system prompt that you might use to show the user your new capabilities.
|
|
209
|
-
|
|
210
|
-
The following example demonstrates how to build an MCP server that provides weather data functionality. While this example shows how to implement resources, resource templates, and tools, in practice you should prefer using tools since they are more flexible and can handle dynamic parameters. The resource and resource template implementations are included here mainly for demonstration purposes of the different MCP capabilities, but a real weather server would likely just expose tools for fetching weather data. (The following steps are for macOS)
|
|
211
|
-
|
|
212
|
-
1. Use the `create-typescript-server` tool to bootstrap a new project in the default MCP servers directory:
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
cd ${await mcpHub.getMcpServersPath()}
|
|
216
|
-
npx @modelcontextprotocol/create-server weather-server
|
|
217
|
-
cd weather-server
|
|
218
|
-
# Install dependencies
|
|
219
|
-
npm install axios
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
This will create a new project with the following structure:
|
|
223
|
-
|
|
224
|
-
```
|
|
225
|
-
weather-server/
|
|
226
|
-
├── package.json
|
|
227
|
-
{
|
|
228
|
-
...
|
|
229
|
-
"type": "module", // added by default, uses ES module syntax (import/export) rather than CommonJS (require/module.exports) (Important to know if you create additional scripts in this server repository like a get-refresh-token.js script)
|
|
230
|
-
"scripts": {
|
|
231
|
-
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
232
|
-
...
|
|
233
|
-
}
|
|
234
|
-
...
|
|
235
|
-
}
|
|
236
|
-
├── tsconfig.json
|
|
237
|
-
└── src/
|
|
238
|
-
└── weather-server/
|
|
239
|
-
└── index.ts # Main server implementation
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
2. Replace `src/index.ts` with the following:
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
#!/usr/bin/env node
|
|
246
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
247
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
248
|
-
import {
|
|
249
|
-
CallToolRequestSchema,
|
|
250
|
-
ErrorCode,
|
|
251
|
-
ListResourcesRequestSchema,
|
|
252
|
-
ListResourceTemplatesRequestSchema,
|
|
253
|
-
ListToolsRequestSchema,
|
|
254
|
-
McpError,
|
|
255
|
-
ReadResourceRequestSchema,
|
|
256
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
257
|
-
import axios from 'axios';
|
|
258
|
-
|
|
259
|
-
const API_KEY = process.env.OPENWEATHER_API_KEY; // provided by MCP config
|
|
260
|
-
if (!API_KEY) {
|
|
261
|
-
throw new Error('OPENWEATHER_API_KEY environment variable is required');
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
interface OpenWeatherResponse {
|
|
265
|
-
main: {
|
|
266
|
-
temp: number;
|
|
267
|
-
humidity: number;
|
|
268
|
-
};
|
|
269
|
-
weather: [{ description: string }];
|
|
270
|
-
wind: { speed: number };
|
|
271
|
-
dt_txt?: string;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const isValidForecastArgs = (
|
|
275
|
-
args: any
|
|
276
|
-
): args is { city: string; days?: number } =>
|
|
277
|
-
typeof args === 'object' &&
|
|
278
|
-
args !== null &&
|
|
279
|
-
typeof args.city === 'string' &&
|
|
280
|
-
(args.days === undefined || typeof args.days === 'number');
|
|
281
|
-
|
|
282
|
-
class WeatherServer {
|
|
283
|
-
private server: Server;
|
|
284
|
-
private axiosInstance;
|
|
285
|
-
|
|
286
|
-
constructor() {
|
|
287
|
-
this.server = new Server(
|
|
288
|
-
{
|
|
289
|
-
name: 'example-weather-server',
|
|
290
|
-
version: '0.1.0',
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
capabilities: {
|
|
294
|
-
resources: {},
|
|
295
|
-
tools: {},
|
|
296
|
-
},
|
|
297
|
-
}
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
this.axiosInstance = axios.create({
|
|
301
|
-
baseURL: 'http://api.openweathermap.org/data/2.5',
|
|
302
|
-
params: {
|
|
303
|
-
appid: API_KEY,
|
|
304
|
-
units: 'metric',
|
|
305
|
-
},
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
this.setupResourceHandlers();
|
|
309
|
-
this.setupToolHandlers();
|
|
310
|
-
|
|
311
|
-
// Error handling
|
|
312
|
-
this.server.onerror = (error) => console.error('[MCP Error]', error);
|
|
313
|
-
process.on('SIGINT', async () => {
|
|
314
|
-
await this.server.close();
|
|
315
|
-
process.exit(0);
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// MCP Resources represent any kind of UTF-8 encoded data that an MCP server wants to make available to clients, such as database records, API responses, log files, and more. Servers define direct resources with a static URI or dynamic resources with a URI template that follows the format `[protocol]://[host]/[path]`.
|
|
320
|
-
private setupResourceHandlers() {
|
|
321
|
-
// For static resources, servers can expose a list of resources:
|
|
322
|
-
this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
323
|
-
resources: [
|
|
324
|
-
// This is a poor example since you could use the resource template to get the same information but this demonstrates how to define a static resource
|
|
325
|
-
{
|
|
326
|
-
uri: `weather://San Francisco/current`, // Unique identifier for San Francisco weather resource
|
|
327
|
-
name: `Current weather in San Francisco`, // Human-readable name
|
|
328
|
-
mimeType: 'application/json', // Optional MIME type
|
|
329
|
-
// Optional description
|
|
330
|
-
description:
|
|
331
|
-
'Real-time weather data for San Francisco including temperature, conditions, humidity, and wind speed',
|
|
332
|
-
},
|
|
333
|
-
],
|
|
334
|
-
}));
|
|
335
|
-
|
|
336
|
-
// For dynamic resources, servers can expose resource templates:
|
|
337
|
-
this.server.setRequestHandler(
|
|
338
|
-
ListResourceTemplatesRequestSchema,
|
|
339
|
-
async () => ({
|
|
340
|
-
resourceTemplates: [
|
|
341
|
-
{
|
|
342
|
-
uriTemplate: 'weather://{city}/current', // URI template (RFC 6570)
|
|
343
|
-
name: 'Current weather for a given city', // Human-readable name
|
|
344
|
-
mimeType: 'application/json', // Optional MIME type
|
|
345
|
-
description: 'Real-time weather data for a specified city', // Optional description
|
|
346
|
-
},
|
|
347
|
-
],
|
|
348
|
-
})
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
// ReadResourceRequestSchema is used for both static resources and dynamic resource templates
|
|
352
|
-
this.server.setRequestHandler(
|
|
353
|
-
ReadResourceRequestSchema,
|
|
354
|
-
async (request) => {
|
|
355
|
-
const match = request.params.uri.match(
|
|
356
|
-
/^weather:\/\/([^/]+)\/current$/
|
|
357
|
-
);
|
|
358
|
-
if (!match) {
|
|
359
|
-
throw new McpError(
|
|
360
|
-
ErrorCode.InvalidRequest,
|
|
361
|
-
`Invalid URI format: ${request.params.uri}`
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
const city = decodeURIComponent(match[1]);
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
const response = await this.axiosInstance.get(
|
|
368
|
-
'weather', // current weather
|
|
369
|
-
{
|
|
370
|
-
params: { q: city },
|
|
371
|
-
}
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
contents: [
|
|
376
|
-
{
|
|
377
|
-
uri: request.params.uri,
|
|
378
|
-
mimeType: 'application/json',
|
|
379
|
-
text: JSON.stringify(
|
|
380
|
-
{
|
|
381
|
-
temperature: response.data.main.temp,
|
|
382
|
-
conditions: response.data.weather[0].description,
|
|
383
|
-
humidity: response.data.main.humidity,
|
|
384
|
-
wind_speed: response.data.wind.speed,
|
|
385
|
-
timestamp: new Date().toISOString(),
|
|
386
|
-
},
|
|
387
|
-
null,
|
|
388
|
-
2
|
|
389
|
-
),
|
|
390
|
-
},
|
|
391
|
-
],
|
|
392
|
-
};
|
|
393
|
-
} catch (error) {
|
|
394
|
-
if (axios.isAxiosError(error)) {
|
|
395
|
-
throw new McpError(
|
|
396
|
-
ErrorCode.InternalError,
|
|
397
|
-
`Weather API error: ${
|
|
398
|
-
error.response?.data.message ?? error.message
|
|
399
|
-
}`
|
|
400
|
-
);
|
|
401
|
-
}
|
|
402
|
-
throw error;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/* MCP Tools enable servers to expose executable functionality to the system. Through these tools, you can interact with external systems, perform computations, and take actions in the real world.
|
|
409
|
-
* - Like resources, tools are identified by unique names and can include descriptions to guide their usage. However, unlike resources, tools represent dynamic operations that can modify state or interact with external systems.
|
|
410
|
-
* - While resources and tools are similar, you should prefer to create tools over resources when possible as they provide more flexibility.
|
|
411
|
-
*/
|
|
412
|
-
private setupToolHandlers() {
|
|
413
|
-
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
414
|
-
tools: [
|
|
415
|
-
{
|
|
416
|
-
name: 'get_forecast', // Unique identifier
|
|
417
|
-
description: 'Get weather forecast for a city', // Human-readable description
|
|
418
|
-
inputSchema: {
|
|
419
|
-
// JSON Schema for parameters
|
|
420
|
-
type: 'object',
|
|
421
|
-
properties: {
|
|
422
|
-
city: {
|
|
423
|
-
type: 'string',
|
|
424
|
-
description: 'City name',
|
|
425
|
-
},
|
|
426
|
-
days: {
|
|
427
|
-
type: 'number',
|
|
428
|
-
description: 'Number of days (1-5)',
|
|
429
|
-
minimum: 1,
|
|
430
|
-
maximum: 5,
|
|
431
|
-
},
|
|
432
|
-
},
|
|
433
|
-
required: ['city'], // Array of required property names
|
|
434
|
-
},
|
|
435
|
-
},
|
|
436
|
-
],
|
|
437
|
-
}));
|
|
438
|
-
|
|
439
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
440
|
-
if (request.params.name !== 'get_forecast') {
|
|
441
|
-
throw new McpError(
|
|
442
|
-
ErrorCode.MethodNotFound,
|
|
443
|
-
`Unknown tool: ${request.params.name}`
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (!isValidForecastArgs(request.params.arguments)) {
|
|
448
|
-
throw new McpError(
|
|
449
|
-
ErrorCode.InvalidParams,
|
|
450
|
-
'Invalid forecast arguments'
|
|
451
|
-
);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const city = request.params.arguments.city;
|
|
455
|
-
const days = Math.min(request.params.arguments.days || 3, 5);
|
|
456
|
-
|
|
457
|
-
try {
|
|
458
|
-
const response = await this.axiosInstance.get<{
|
|
459
|
-
list: OpenWeatherResponse[];
|
|
460
|
-
}>('forecast', {
|
|
461
|
-
params: {
|
|
462
|
-
q: city,
|
|
463
|
-
cnt: days * 8,
|
|
464
|
-
},
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
return {
|
|
468
|
-
content: [
|
|
469
|
-
{
|
|
470
|
-
type: 'text',
|
|
471
|
-
text: JSON.stringify(response.data.list, null, 2),
|
|
472
|
-
},
|
|
473
|
-
],
|
|
474
|
-
};
|
|
475
|
-
} catch (error) {
|
|
476
|
-
if (axios.isAxiosError(error)) {
|
|
477
|
-
return {
|
|
478
|
-
content: [
|
|
479
|
-
{
|
|
480
|
-
type: 'text',
|
|
481
|
-
text: `Weather API error: ${
|
|
482
|
-
error.response?.data.message ?? error.message
|
|
483
|
-
}`,
|
|
484
|
-
},
|
|
485
|
-
],
|
|
486
|
-
isError: true,
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
throw error;
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
async run() {
|
|
495
|
-
const transport = new StdioServerTransport();
|
|
496
|
-
await this.server.connect(transport);
|
|
497
|
-
console.error('Weather MCP server running on stdio');
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
const server = new WeatherServer();
|
|
502
|
-
server.run().catch(console.error);
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
(Remember: This is just an example–you may use different dependencies, break the implementation up into multiple files, etc.)
|
|
506
|
-
|
|
507
|
-
3. Build and compile the executable JavaScript file
|
|
508
|
-
|
|
509
|
-
```bash
|
|
510
|
-
npm run build
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
4. Whenever you need an environment variable such as an API key to configure the MCP server, walk the user through the process of getting the key. For example, they may need to create an account and go to a developer dashboard to generate the key. Provide step-by-step instructions and URLs to make it easy for the user to retrieve the necessary information. Then use the ask_followup_question tool to ask the user for the key, in this case the OpenWeather API key.
|
|
514
|
-
|
|
515
|
-
5. Install the MCP Server by adding the MCP server configuration to the settings file located at '${await mcpHub.getMcpSettingsFilePath()}'. The settings file may have other MCP servers already configured, so you would read it first and then add your new server to the existing `mcpServers` object.
|
|
516
|
-
|
|
517
|
-
```json
|
|
518
|
-
{
|
|
519
|
-
"mcpServers": {
|
|
520
|
-
...,
|
|
521
|
-
"weather": {
|
|
522
|
-
"command": "node",
|
|
523
|
-
"args": ["/path/to/weather-server/build/index.js"],
|
|
524
|
-
"env": {
|
|
525
|
-
"OPENWEATHER_API_KEY": "user-provided-api-key"
|
|
526
|
-
}
|
|
527
|
-
},
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
(Note: the user may also ask you to install the MCP server to the Claude desktop app, in which case you would read then modify `~/Library/Application\ Support/Claude/claude_desktop_config.json` on macOS for example. It follows the same format of a top level `mcpServers` object.)
|
|
533
|
-
|
|
534
|
-
6. After you have edited the MCP settings configuration file, the system will automatically run all the servers and expose the available tools and resources in the 'Connected MCP Servers' section.
|
|
535
|
-
|
|
536
|
-
7. Now that you have access to these new tools and resources, you may suggest ways the user can command you to invoke them - for example, with this new weather tool now available, you can invite the user to ask "what's the weather in San Francisco?"
|
|
537
|
-
|
|
538
|
-
## Editing MCP Servers
|
|
539
|
-
|
|
540
|
-
The user may ask to add tools or resources that may make sense to add to an existing MCP server (listed under 'Connected MCP Servers' above: {{ server_names }}, e.g. if it would use the same API. This would be possible if you can locate the MCP server repository on the user's system by looking at the server arguments for a filepath. You might then use list_files and read_file to explore the files in the repository, and use replace_in_file to make changes to the files.
|
|
541
|
-
|
|
542
|
-
However some MCP servers may be running from installed packages rather than a local repository, in which case it may make more sense to create a new MCP server.
|
|
543
|
-
|
|
200
|
+
|
|
544
201
|
# MCP Servers Are Not Always Necessary
|
|
545
202
|
|
|
546
203
|
The user may not always request the use or creation of MCP servers. Instead, they might provide tasks that can be completed with existing tools. While using the MCP SDK to extend your capabilities can be useful, it's important to understand that this is just one specialized type of task you can accomplish. You should only implement MCP servers when the user explicitly requests it (e.g., "add a tool that...").
|
|
547
204
|
|
|
548
205
|
Remember: The MCP documentation and example provided above are to help you understand and work with existing MCP servers or create new ones when requested by the user. You already have access to tools and capabilities that can be used to accomplish a wide range of tasks.
|
|
206
|
+
|
|
207
|
+
用户的问题是:
|
|
208
|
+
|
|
209
|
+
{{query}}
|
|
210
|
+
|
|
211
|
+
请选择前面罗列的 MCP Servers 信息,并且按规定格式来选择前面罗列的 MCP Servers,并选择合适的工具来回答。
|
|
212
|
+
注意,如果没有合适的工具,你可以直接回答没有可用工具。
|
|
549
213
|
"""
|
|
550
214
|
return {
|
|
551
215
|
"connected_servers_info": self.get_connected_servers_info(),
|
|
@@ -600,34 +264,20 @@ class McpExecutor:
|
|
|
600
264
|
|
|
601
265
|
return results
|
|
602
266
|
|
|
603
|
-
async def run(self, conversations: List[Dict[str, Any]]):
|
|
604
|
-
new_conversations = [{
|
|
605
|
-
"role": "user",
|
|
606
|
-
"content": self.mcp_prompt.prompt()
|
|
607
|
-
}, {
|
|
608
|
-
"role": "assistant",
|
|
609
|
-
"content": "I have read the tools usage instructions."
|
|
610
|
-
}] + conversations
|
|
611
|
-
|
|
267
|
+
async def run(self, conversations: List[Dict[str, Any]]):
|
|
612
268
|
all_tool_results = []
|
|
613
269
|
|
|
270
|
+
query = conversations[-1]["content"]
|
|
271
|
+
new_conversations = conversations[0:-1]+[{
|
|
272
|
+
"role": "user",
|
|
273
|
+
"content": self.mcp_prompt.prompt(query=query)
|
|
274
|
+
}]
|
|
275
|
+
|
|
614
276
|
v = self.llm.chat_oai(conversations=new_conversations)
|
|
615
|
-
content = v[0].output
|
|
277
|
+
content = v[0].output
|
|
278
|
+
|
|
616
279
|
tools = await self.extract_mcp_calls(content)
|
|
617
|
-
|
|
618
|
-
# results = await self.execute_mcp_tools(tools)
|
|
619
|
-
# all_tool_results += results
|
|
620
|
-
# str_results = "\n\n".join(self.format_mcp_result(result) for result in results)
|
|
621
|
-
# new_conversations += [{
|
|
622
|
-
# "role": "assistant",
|
|
623
|
-
# "content": f"Tool results: {str_results}"
|
|
624
|
-
# },{
|
|
625
|
-
# "role": "user",
|
|
626
|
-
# "content": "continue"
|
|
627
|
-
# }]
|
|
628
|
-
# v = self.llm.chat_oai(conversations=new_conversations)
|
|
629
|
-
# content = v[0].output
|
|
630
|
-
# tools = await self.extract_mcp_calls(content)
|
|
280
|
+
|
|
631
281
|
if tools:
|
|
632
282
|
results = await self.execute_mcp_tools(tools)
|
|
633
283
|
all_tool_results += results
|
|
@@ -646,12 +296,10 @@ class McpExecutor:
|
|
|
646
296
|
"""
|
|
647
297
|
if result is None:
|
|
648
298
|
return "(No result)"
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
# if isinstance(result, mcp_types.ReadResourceResult):
|
|
654
|
-
# return result.contents
|
|
299
|
+
if isinstance(result, mcp_types.CallToolResult):
|
|
300
|
+
if len(result.content) ==1:
|
|
301
|
+
return result.content[0].text
|
|
302
|
+
|
|
655
303
|
return json.dumps(result.model_dump(), indent=2, ensure_ascii=False)
|
|
656
304
|
|
|
657
305
|
async def execute_mcp_tools(self, tools: List[Union[McpToolCall, McpResourceAccess]]) -> List[Any]:
|
autocoder/index/index.py
CHANGED
autocoder/rag/types.py
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import pydantic
|
|
6
|
+
from typing import Dict, Any, Optional, List
|
|
7
|
+
import psutil
|
|
8
|
+
import glob
|
|
9
|
+
|
|
10
|
+
class RAGServiceInfo(pydantic.BaseModel):
|
|
11
|
+
host: str
|
|
12
|
+
port: int
|
|
13
|
+
model: str
|
|
14
|
+
args: Dict[str, Any]
|
|
15
|
+
_pid: int
|
|
16
|
+
_timestamp:str
|
|
17
|
+
|
|
18
|
+
def save(self):
|
|
19
|
+
# Get home directory in a cross-platform way
|
|
20
|
+
home_dir = os.path.expanduser("~")
|
|
21
|
+
rag_dir = os.path.join(home_dir, ".auto-coder", "rags")
|
|
22
|
+
os.makedirs(rag_dir, exist_ok=True)
|
|
23
|
+
|
|
24
|
+
# Generate filename
|
|
25
|
+
filename = f"{self.host}_{self.port}.json"
|
|
26
|
+
filepath = os.path.join(rag_dir, filename)
|
|
27
|
+
|
|
28
|
+
# Save to JSON
|
|
29
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
30
|
+
json.dump(self.model_dump(), f, ensure_ascii=False, indent=2)
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def load(cls, host: str, port: int) -> Optional["RAGServiceInfo"]:
|
|
34
|
+
"""Load RAGServiceInfo from file"""
|
|
35
|
+
home_dir = os.path.expanduser("~")
|
|
36
|
+
rag_dir = os.path.join(home_dir, ".auto-coder", "rags")
|
|
37
|
+
filename = f"{host}_{port}.json"
|
|
38
|
+
filepath = os.path.join(rag_dir, filename)
|
|
39
|
+
|
|
40
|
+
if not os.path.exists(filepath):
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
44
|
+
data = json.load(f)
|
|
45
|
+
return cls(**data)
|
|
46
|
+
|
|
47
|
+
def is_alive(self) -> bool:
|
|
48
|
+
"""Check if the RAG service process is still running using psutil"""
|
|
49
|
+
try:
|
|
50
|
+
process = psutil.Process(self._pid)
|
|
51
|
+
return process.is_running()
|
|
52
|
+
except psutil.NoSuchProcess:
|
|
53
|
+
return False
|
|
54
|
+
except psutil.AccessDenied:
|
|
55
|
+
# Process exists but we don't have permission to access it
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def load_all(cls) -> List["RAGServiceInfo"]:
|
|
60
|
+
"""Load all RAGServiceInfo from ~/.auto-coder/rags directory"""
|
|
61
|
+
home_dir = os.path.expanduser("~")
|
|
62
|
+
rag_dir = os.path.join(home_dir, ".auto-coder", "rags")
|
|
63
|
+
|
|
64
|
+
if not os.path.exists(rag_dir):
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
service_infos = []
|
|
68
|
+
for filepath in glob.glob(os.path.join(rag_dir, "*.json")):
|
|
69
|
+
try:
|
|
70
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
71
|
+
data = json.load(f)
|
|
72
|
+
service_info = cls(**data)
|
|
73
|
+
service_infos.append(service_info)
|
|
74
|
+
except Exception as e:
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
return service_infos
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.218"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|