feat(ci): use JSON format and auto-convert file references to URLs in issue replies (#597)

* Initial plan

* feat(ci): improve auto-reply-issue with JSON format and URL conversion

- Update system prompt to request JSON response format instead of text tag
- Add JSON parsing with fallback to legacy format for backward compatibility
- Add automatic URL conversion for markdown doc references (doc/*.md -> https://ddns.newfuture.cc/doc/*.html)
- Add automatic URL conversion for code file references (ddns/*.py -> GitHub links)
- Add response_format: json_object to API request for structured responses
- Add comprehensive file reference guidelines in system prompt

Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(ci): remove redundant URL conversion mentions from AI prompt

The URL conversion is handled in the workflow code, so the AI prompt should only instruct to use backticks with relative paths, not mention the post-processing conversion.

Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com>

* refactor(ci): let AI generate markdown links directly in response

Simplify workflow logic by having AI output markdown links directly instead of post-processing. This makes the code simpler and reduces complexity in the workflow.

Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com>
Co-authored-by: New Future <NewFuture@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot
2025-11-18 07:36:19 +00:00
committed by GitHub
co-authored by NewFuture Copilot New Future
parent 5d1694609e
commit 180b6efb78
2 changed files with 70 additions and 17 deletions
+39 -8
View File
@@ -12,23 +12,54 @@ Your role is to provide friendly, informative responses to GitHub issues.
- Uses Python standard library only (no external dependencies)
- Supports Python 2.7 and 3.x
## Issue Classification
## Response Format
**IMPORTANT**: You must classify each issue into ONE of these categories:
**IMPORTANT**: You must return your response as a JSON object with the following structure:
```json
{
"classification": "bug|feature|question",
"response": "Your detailed response here..."
}
```
### Classification Categories
Classify each issue into ONE of these categories:
- **bug**: Software defects, errors, crashes, or unexpected behavior
- **feature**: New feature requests, enhancements, or improvements
- **question**: Questions about usage, configuration, documentation, or general inquiries
Return your classification at the START of your response using ONE of the following formats:
```
### Response Content Guidelines
When writing the "response" field:
- **Respond in the same language as the issue title and content** (detect and match the user's language - Chinese, English, or other languages)
- Keep responses concise but helpful
- Use proper markdown formatting for code blocks and inline code
- Reference files and documentation using markdown links
### File References
When referencing files in your response, use these formats:
1. **Documentation files**: Use markdown links that convert `.md` to `.html` URLs
- Format: `[doc/providers/aliesa.md](https://ddns.newfuture.cc/doc/providers/aliesa.html)`
- Format: `[doc/config/cli.md](https://ddns.newfuture.cc/doc/config/cli.html)`
2. **Code files**: Use markdown links to GitHub repository
- Format: `[ddns/provider/_base.py](https://github.com/NewFuture/DDNS/blob/master/ddns/provider/_base.py)`
- Format: `[tests/test_cache.py](https://github.com/NewFuture/DDNS/blob/master/tests/test_cache.py)`
3. **Code blocks**: Use proper markdown code fences with language identifiers:
````markdown
```python
# Your code here
```
````
4. **Inline code**: Use backticks for commands and code snippets: `` `ddns --debug` `` or `` `variable_name` ``
## Response Guidelines
When responding to issues:
1. Start with the classification tag in the exact format above
2. Be welcoming and professional
3. **Respond in the same language as the issue title and content** (detect and match the user's language - Chinese, English, or other languages)
4. Keep responses concise but helpful
1. Be welcoming and professional
2. Be specific and actionable in your guidance
### Response Strategy by Classification
+31 -9
View File
@@ -134,6 +134,7 @@ jobs:
],
temperature: 1,
max_completion_tokens: 2000,
response_format: { type: "json_object" }
})
});
@@ -157,21 +158,42 @@ jobs:
return;
}
const aiResponse = data.choices[0].message.content.trim();
let aiResponse = data.choices[0].message.content.trim();
// Extract classification from response
const classificationMatch = aiResponse.match(/\[CLASSIFICATION:\s*(bug|feature|question)\]/i);
// Try to parse JSON response
let classification = null;
let commentBody = aiResponse;
if (classificationMatch) {
classification = classificationMatch[1].toLowerCase();
// Remove classification tag from the comment body
commentBody = aiResponse.replace(/\[CLASSIFICATION:\s*(bug|feature|question)\]\s*/i, '').trim();
console.log(`Issue classified as: ${classification}`);
try {
// Remove markdown code fences if present
let jsonContent = aiResponse;
if (aiResponse.startsWith('```json') || aiResponse.startsWith('```')) {
jsonContent = aiResponse.replace(/^```(?:json)?\s*\n/, '').replace(/\n```\s*$/, '').trim();
}
const parsedResponse = JSON.parse(jsonContent);
if (parsedResponse.classification && parsedResponse.response) {
classification = parsedResponse.classification.toLowerCase();
commentBody = parsedResponse.response;
console.log(`Issue classified as: ${classification} (JSON format)`);
} else {
console.log('JSON response missing required fields, falling back to text format');
}
} catch (jsonError) {
console.log(`Failed to parse JSON response: ${jsonError.message}`);
console.log('Falling back to legacy text format extraction');
// Fallback: Try legacy format with classification tag
const classificationMatch = aiResponse.match(/\[CLASSIFICATION:\s*(bug|feature|question)\]/i);
if (classificationMatch) {
classification = classificationMatch[1].toLowerCase();
commentBody = aiResponse.replace(/\[CLASSIFICATION:\s*(bug|feature|question)\]\s*/i, '').trim();
console.log(`Issue classified as: ${classification} (legacy format)`);
}
}
// Post the response as a comment (without classification tag)
// Post the response as a comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,