@lobehub/chat 1.137.4 → 1.137.6
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/.github/scripts/auto-close-duplicates.ts +260 -0
- package/.github/workflows/claude-dedupe-issues.yml +33 -0
- package/.github/workflows/claude-issue-triage.yml +199 -0
- package/.github/workflows/desktop-pr-build.yml +3 -3
- package/.github/workflows/docker-database.yml +1 -1
- package/.github/workflows/docker-pglite.yml +1 -1
- package/.github/workflows/docker.yml +1 -1
- package/.github/workflows/issue-auto-close-duplicates.yml +30 -0
- package/.github/workflows/release-desktop-beta.yml +1 -1
- package/CHANGELOG.md +51 -0
- package/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/context-engine/src/processors/MessageContent.ts +4 -2
- package/packages/context-engine/src/processors/__tests__/MessageContent.test.ts +11 -14
- package/packages/model-bank/src/aiModels/google.ts +7 -7
- package/packages/model-bank/src/aiModels/vertexai.ts +63 -2
- package/packages/utils/package.json +2 -1
- package/packages/utils/src/url.test.ts +19 -19
- package/packages/utils/src/url.ts +7 -11
- package/src/server/modules/ModelRuntime/index.test.ts +31 -0
- package/src/server/modules/ModelRuntime/index.ts +43 -0
- package/src/services/chat/chat.test.ts +38 -17
- package/src/services/chat/clientModelRuntime.test.ts +3 -3
- package/src/store/chat/slices/aiChat/actions/__tests__/fixtures.ts +66 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +893 -650
- package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +106 -0
- package/src/app/(backend)/webapi/chat/vertexai/route.ts +0 -38
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
// eslint-disable-next-line no-var
|
|
6
|
+
var process: {
|
|
7
|
+
env: Record<string, string | undefined>;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface GitHubIssue {
|
|
12
|
+
created_at: string;
|
|
13
|
+
number: number;
|
|
14
|
+
title: string;
|
|
15
|
+
user: { id: number };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface GitHubComment {
|
|
19
|
+
body: string;
|
|
20
|
+
created_at: string;
|
|
21
|
+
id: number;
|
|
22
|
+
user: { id: number; type: string };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface GitHubReaction {
|
|
26
|
+
content: string;
|
|
27
|
+
user: { id: number };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function githubRequest<T>(
|
|
31
|
+
endpoint: string,
|
|
32
|
+
token: string,
|
|
33
|
+
method: string = 'GET',
|
|
34
|
+
body?: any,
|
|
35
|
+
): Promise<T> {
|
|
36
|
+
const response = await fetch(`https://api.github.com${endpoint}`, {
|
|
37
|
+
headers: {
|
|
38
|
+
'Accept': 'application/vnd.github.v3+json',
|
|
39
|
+
'Authorization': `Bearer ${token}`,
|
|
40
|
+
'User-Agent': 'auto-close-duplicates-script',
|
|
41
|
+
...(body && { 'Content-Type': 'application/json' }),
|
|
42
|
+
},
|
|
43
|
+
method,
|
|
44
|
+
...(body && { body: JSON.stringify(body) }),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(`GitHub API request failed: ${response.status} ${response.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function extractDuplicateIssueNumber(commentBody: string): number | null {
|
|
55
|
+
// Try to match #123 format first
|
|
56
|
+
let match = commentBody.match(/#(\d+)/);
|
|
57
|
+
if (match) {
|
|
58
|
+
return parseInt(match[1], 10);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Try to match GitHub issue URL format: https://github.com/owner/repo/issues/123
|
|
62
|
+
match = commentBody.match(/github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/);
|
|
63
|
+
if (match) {
|
|
64
|
+
return parseInt(match[1], 10);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function closeIssueAsDuplicate(
|
|
71
|
+
owner: string,
|
|
72
|
+
repo: string,
|
|
73
|
+
issueNumber: number,
|
|
74
|
+
duplicateOfNumber: number,
|
|
75
|
+
token: string,
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
await githubRequest(`/repos/${owner}/${repo}/issues/${issueNumber}`, token, 'PATCH', {
|
|
78
|
+
labels: ['duplicate'],
|
|
79
|
+
state: 'closed',
|
|
80
|
+
state_reason: 'duplicate',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await githubRequest(`/repos/${owner}/${repo}/issues/${issueNumber}/comments`, token, 'POST', {
|
|
84
|
+
body: `This issue has been automatically closed as a duplicate of #${duplicateOfNumber}.
|
|
85
|
+
|
|
86
|
+
If this is incorrect, please re-open this issue or create a new one.
|
|
87
|
+
|
|
88
|
+
🤖 Generated with [Claude Code](https://claude.ai/code)`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function autoCloseDuplicates(): Promise<void> {
|
|
93
|
+
console.log('[DEBUG] Starting auto-close duplicates script');
|
|
94
|
+
|
|
95
|
+
const token = process.env.GITHUB_TOKEN;
|
|
96
|
+
if (!token) {
|
|
97
|
+
throw new Error('GITHUB_TOKEN environment variable is required');
|
|
98
|
+
}
|
|
99
|
+
console.log('[DEBUG] GitHub token found');
|
|
100
|
+
|
|
101
|
+
const owner = process.env.GITHUB_REPOSITORY_OWNER || 'lobehub';
|
|
102
|
+
const repo = process.env.GITHUB_REPOSITORY_NAME || 'lobe-chat';
|
|
103
|
+
console.log(`[DEBUG] Repository: ${owner}/${repo}`);
|
|
104
|
+
|
|
105
|
+
const threeDaysAgo = new Date();
|
|
106
|
+
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
|
|
107
|
+
console.log(`[DEBUG] Checking for duplicate comments older than: ${threeDaysAgo.toISOString()}`);
|
|
108
|
+
|
|
109
|
+
console.log('[DEBUG] Fetching open issues created more than 3 days ago...');
|
|
110
|
+
const allIssues: GitHubIssue[] = [];
|
|
111
|
+
let page = 1;
|
|
112
|
+
const perPage = 100;
|
|
113
|
+
|
|
114
|
+
// eslint-disable-next-line no-constant-condition
|
|
115
|
+
while (true) {
|
|
116
|
+
const pageIssues: GitHubIssue[] = await githubRequest(
|
|
117
|
+
`/repos/${owner}/${repo}/issues?state=open&per_page=${perPage}&page=${page}`,
|
|
118
|
+
token,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (pageIssues.length === 0) break;
|
|
122
|
+
|
|
123
|
+
// Filter for issues created more than 3 days ago
|
|
124
|
+
const oldEnoughIssues = pageIssues.filter(
|
|
125
|
+
(issue) => new Date(issue.created_at) <= threeDaysAgo,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
allIssues.push(...oldEnoughIssues);
|
|
129
|
+
page++;
|
|
130
|
+
|
|
131
|
+
// Safety limit to avoid infinite loops
|
|
132
|
+
if (page > 20) break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const issues = allIssues;
|
|
136
|
+
console.log(`[DEBUG] Found ${issues.length} open issues`);
|
|
137
|
+
|
|
138
|
+
let processedCount = 0;
|
|
139
|
+
let candidateCount = 0;
|
|
140
|
+
|
|
141
|
+
for (const issue of issues) {
|
|
142
|
+
processedCount++;
|
|
143
|
+
console.log(
|
|
144
|
+
`[DEBUG] Processing issue #${issue.number} (${processedCount}/${issues.length}): ${issue.title}`,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
console.log(`[DEBUG] Fetching comments for issue #${issue.number}...`);
|
|
148
|
+
const comments: GitHubComment[] = await githubRequest(
|
|
149
|
+
`/repos/${owner}/${repo}/issues/${issue.number}/comments`,
|
|
150
|
+
token,
|
|
151
|
+
);
|
|
152
|
+
console.log(`[DEBUG] Issue #${issue.number} has ${comments.length} comments`);
|
|
153
|
+
|
|
154
|
+
const dupeComments = comments.filter(
|
|
155
|
+
(comment) =>
|
|
156
|
+
comment.body.includes('Found') &&
|
|
157
|
+
comment.body.includes('possible duplicate') &&
|
|
158
|
+
comment.user.type === 'Bot',
|
|
159
|
+
);
|
|
160
|
+
console.log(
|
|
161
|
+
`[DEBUG] Issue #${issue.number} has ${dupeComments.length} duplicate detection comments`,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (dupeComments.length === 0) {
|
|
165
|
+
console.log(`[DEBUG] Issue #${issue.number} - no duplicate comments found, skipping`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const lastDupeComment = dupeComments.at(-1);
|
|
170
|
+
// @ts-ignore
|
|
171
|
+
const dupeCommentDate = new Date(lastDupeComment.created_at);
|
|
172
|
+
console.log(
|
|
173
|
+
`[DEBUG] Issue #${
|
|
174
|
+
issue.number
|
|
175
|
+
} - most recent duplicate comment from: ${dupeCommentDate.toISOString()}`,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (dupeCommentDate > threeDaysAgo) {
|
|
179
|
+
console.log(`[DEBUG] Issue #${issue.number} - duplicate comment is too recent, skipping`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
console.log(
|
|
183
|
+
`[DEBUG] Issue #${issue.number} - duplicate comment is old enough (${Math.floor(
|
|
184
|
+
(Date.now() - dupeCommentDate.getTime()) / (1000 * 60 * 60 * 24),
|
|
185
|
+
)} days)`,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const commentsAfterDupe = comments.filter(
|
|
189
|
+
(comment) => new Date(comment.created_at) > dupeCommentDate,
|
|
190
|
+
);
|
|
191
|
+
console.log(
|
|
192
|
+
`[DEBUG] Issue #${issue.number} - ${commentsAfterDupe.length} comments after duplicate detection`,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
if (commentsAfterDupe.length > 0) {
|
|
196
|
+
console.log(
|
|
197
|
+
`[DEBUG] Issue #${issue.number} - has activity after duplicate comment, skipping`,
|
|
198
|
+
);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(`[DEBUG] Issue #${issue.number} - checking reactions on duplicate comment...`);
|
|
203
|
+
const reactions: GitHubReaction[] = await githubRequest(
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
`/repos/${owner}/${repo}/issues/comments/${lastDupeComment.id}/reactions`,
|
|
206
|
+
token,
|
|
207
|
+
);
|
|
208
|
+
console.log(
|
|
209
|
+
`[DEBUG] Issue #${issue.number} - duplicate comment has ${reactions.length} reactions`,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const authorThumbsDown = reactions.some(
|
|
213
|
+
(reaction) => reaction.user.id === issue.user.id && reaction.content === '-1',
|
|
214
|
+
);
|
|
215
|
+
console.log(
|
|
216
|
+
`[DEBUG] Issue #${issue.number} - author thumbs down reaction: ${authorThumbsDown}`,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
if (authorThumbsDown) {
|
|
220
|
+
console.log(
|
|
221
|
+
`[DEBUG] Issue #${issue.number} - author disagreed with duplicate detection, skipping`,
|
|
222
|
+
);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
const duplicateIssueNumber = extractDuplicateIssueNumber(lastDupeComment.body);
|
|
228
|
+
if (!duplicateIssueNumber) {
|
|
229
|
+
console.log(
|
|
230
|
+
`[DEBUG] Issue #${issue.number} - could not extract duplicate issue number from comment, skipping`,
|
|
231
|
+
);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
candidateCount++;
|
|
236
|
+
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
console.log(
|
|
240
|
+
`[INFO] Auto-closing issue #${issue.number} as duplicate of #${duplicateIssueNumber}: ${issueUrl}`,
|
|
241
|
+
);
|
|
242
|
+
await closeIssueAsDuplicate(owner, repo, issue.number, duplicateIssueNumber, token);
|
|
243
|
+
console.log(
|
|
244
|
+
`[SUCCESS] Successfully closed issue #${issue.number} as duplicate of #${duplicateIssueNumber}`,
|
|
245
|
+
);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error(`[ERROR] Failed to close issue #${issue.number} as duplicate: ${error}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
console.log(
|
|
252
|
+
`[DEBUG] Script completed. Processed ${processedCount} issues, found ${candidateCount} candidates for auto-close`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// eslint-disable-next-line unicorn/prefer-top-level-await
|
|
257
|
+
autoCloseDuplicates().catch(console.error);
|
|
258
|
+
|
|
259
|
+
// Make it a module
|
|
260
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Claude Issue Dedupe
|
|
2
|
+
description: Automatically dedupe GitHub issues using Claude Code
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [opened]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
issue_number:
|
|
9
|
+
description: 'Issue number to process for duplicate detection'
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude-dedupe-issues:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
timeout-minutes: 10
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
issues: write
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout repository
|
|
23
|
+
uses: actions/checkout@v5
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 1
|
|
26
|
+
|
|
27
|
+
- name: Run Claude Code slash command
|
|
28
|
+
uses: anthropics/claude-code-base-action@beta
|
|
29
|
+
with:
|
|
30
|
+
prompt: '/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}'
|
|
31
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
32
|
+
claude_env: |
|
|
33
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
name: Claude Issue Triage
|
|
2
|
+
description: Automatically triage GitHub issues using Claude Code
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [opened, labeled]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
triage-issue:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
timeout-minutes: 10
|
|
11
|
+
# Only run on issue opened, or when "trigger:triage" label is added
|
|
12
|
+
if: github.event.action == 'opened' || (github.event.action == 'labeled' && github.event.label.name == 'trigger:triage')
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
issues: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout repository
|
|
19
|
+
uses: actions/checkout@v5
|
|
20
|
+
|
|
21
|
+
- name: Copy team assignment guide
|
|
22
|
+
run: |
|
|
23
|
+
mkdir -p /tmp/claude-prompts
|
|
24
|
+
cp .claude/prompts/team-assignment.md /tmp/claude-prompts/
|
|
25
|
+
|
|
26
|
+
- name: Create triage prompt
|
|
27
|
+
run: |
|
|
28
|
+
mkdir -p /tmp/claude-prompts
|
|
29
|
+
cat > /tmp/claude-prompts/triage-prompt.md << 'EOF'
|
|
30
|
+
You're an issue triage assistant for GitHub issues. Your task is to analyze issues, apply appropriate labels, and mention the responsible team member.
|
|
31
|
+
|
|
32
|
+
REPOSITORY: ${{ github.repository }}
|
|
33
|
+
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
|
34
|
+
|
|
35
|
+
## WORKFLOW
|
|
36
|
+
|
|
37
|
+
### Step 1: Get Available Labels
|
|
38
|
+
```bash
|
|
39
|
+
gh label list --json name,description --limit 300
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 2: Get Issue Details
|
|
43
|
+
```bash
|
|
44
|
+
gh issue view ${{ github.event.issue.number }} --json number,title,body,labels,comments
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Step 3: Read Team Assignment Guide
|
|
48
|
+
```bash
|
|
49
|
+
cat /tmp/claude-prompts/team-assignment.md
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Step 4: Analyze and Select Labels
|
|
53
|
+
|
|
54
|
+
Extract information from the issue template:
|
|
55
|
+
- 📦 Platform field → platform:web/desktop/mobile
|
|
56
|
+
- 💻 Operating System → os:windows/macos/linux/ios
|
|
57
|
+
- 🌐 Browser → device:pc/mobile
|
|
58
|
+
- 📦 Deployment mode → deployment:server/client/pglite
|
|
59
|
+
- Platform (hosting) → hosting:cloud/self-host/vercel/zeabur/railway
|
|
60
|
+
|
|
61
|
+
**LABEL CATEGORIES:**
|
|
62
|
+
|
|
63
|
+
**a) Issue Type (REQUIRED - select ONE):**
|
|
64
|
+
- 🐛 Bug, 🌠 Feature Request, 💄 Design, 📝 Documentation, ⚡️ Performance
|
|
65
|
+
|
|
66
|
+
**b) Priority (select ONE if applicable):**
|
|
67
|
+
- priority:high - Critical, maintainer mentions "urgent"/"serious"/"critical"
|
|
68
|
+
- priority:medium - Important, affects multiple users
|
|
69
|
+
- priority:low - Nice to have, minor issues
|
|
70
|
+
|
|
71
|
+
**c) Platform (select ALL applicable):**
|
|
72
|
+
- platform:web, platform:desktop, platform:mobile
|
|
73
|
+
|
|
74
|
+
**d) Device (for platform:web, select ONE):**
|
|
75
|
+
- device:pc, device:mobile
|
|
76
|
+
|
|
77
|
+
**e) Operating System (select ALL applicable):**
|
|
78
|
+
- os:windows, os:macos, os:linux, os:ios
|
|
79
|
+
|
|
80
|
+
**f) Hosting Platform (select ONE):**
|
|
81
|
+
- hosting:cloud, hosting:self-host, hosting:vercel, hosting:zeabur, hosting:railway
|
|
82
|
+
|
|
83
|
+
**g) Deployment Mode (select ONE if mentioned):**
|
|
84
|
+
- deployment:server, deployment:client, deployment:pglite
|
|
85
|
+
|
|
86
|
+
**h) Model Provider (select ALL applicable):**
|
|
87
|
+
- provider:openai, provider:gemini, provider:claude, provider:deepseek
|
|
88
|
+
- provider:google, provider:ollama, provider:azure, provider:bedrock, provider:vertex
|
|
89
|
+
|
|
90
|
+
**i) Feature/Component (select ALL applicable):**
|
|
91
|
+
- feature:settings, feature:agent, feature:topic, feature:marketplace
|
|
92
|
+
- feature:streaming, feature:tool, feature:sync, feature:export
|
|
93
|
+
- feature:search, feature:auth, feature:files, feature:knowledge-base
|
|
94
|
+
- feature:tts, feature:vision, feature:mcp, feature:editor, feature:thread
|
|
95
|
+
- feature:image, feature:api, feature:dalle, feature:plugin, feature:markdown
|
|
96
|
+
- feature:group-chat, feature:memory, feature:team-workspace
|
|
97
|
+
|
|
98
|
+
**j) Workflow/Status:**
|
|
99
|
+
- Duplicate - Only if duplicate of OPEN issue
|
|
100
|
+
- needs-reproduction, good-first-issue, 🤔 Need Reproduce
|
|
101
|
+
|
|
102
|
+
**IMPORTANT RULES:**
|
|
103
|
+
- Read issue template fields carefully
|
|
104
|
+
- Check maintainer comments for priority/status
|
|
105
|
+
- Use ALL applicable labels from different categories
|
|
106
|
+
- Always use prefixes (feature:, provider:, os:, platform:, etc.)
|
|
107
|
+
|
|
108
|
+
### Step 5: Apply Labels
|
|
109
|
+
|
|
110
|
+
Add labels:
|
|
111
|
+
```bash
|
|
112
|
+
gh issue edit ${{ github.event.issue.number }} --add-label "label1,label2,label3"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Remove "unconfirm" if adding other labels:
|
|
116
|
+
```bash
|
|
117
|
+
gh issue edit ${{ github.event.issue.number }} --remove-label "unconfirm"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Execute the commands now.**
|
|
121
|
+
|
|
122
|
+
### Step 6: Determine Team Member
|
|
123
|
+
|
|
124
|
+
Based on the team assignment guide and applied labels, determine who to mention.
|
|
125
|
+
|
|
126
|
+
**Priority Order:**
|
|
127
|
+
1. Specific feature owner (feature:knowledge-base → @RiverTwilight)
|
|
128
|
+
2. Platform owner (platform:mobile → @sudongyuer)
|
|
129
|
+
3. Provider owner (provider:* → @sxjeru)
|
|
130
|
+
4. Component owner (💄 Design → @canisminor1990)
|
|
131
|
+
5. Infrastructure owner (deployment:* → @nekomeowww)
|
|
132
|
+
6. General maintainer (@ONLY-yours)
|
|
133
|
+
7. Last resort (@arvinxx)
|
|
134
|
+
|
|
135
|
+
**Special Cases:**
|
|
136
|
+
- Multiple owners: Mention primary + secondary
|
|
137
|
+
- priority:high: Mention owner + @arvinxx
|
|
138
|
+
|
|
139
|
+
### Step 7: Post Comment
|
|
140
|
+
|
|
141
|
+
Format the comment (1-2 sentences):
|
|
142
|
+
|
|
143
|
+
**Single owner:**
|
|
144
|
+
```
|
|
145
|
+
@username - This is a [feature/component] issue. Please take a look.
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Multiple owners:**
|
|
149
|
+
```
|
|
150
|
+
@user1 @user2 - This involves [features]. Please coordinate.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**High priority:**
|
|
154
|
+
```
|
|
155
|
+
@owner @arvinxx - High priority [feature] issue.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Post the comment:
|
|
159
|
+
```bash
|
|
160
|
+
gh issue comment ${{ github.event.issue.number }} --body "@username - [message]"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Execute the command now.**
|
|
164
|
+
|
|
165
|
+
### Step 8: Output Summary
|
|
166
|
+
|
|
167
|
+
Log your reasoning (2-4 sentences):
|
|
168
|
+
- Labels applied and why
|
|
169
|
+
- Team member(s) mentioned and reason
|
|
170
|
+
- Key factors from issue template/comments
|
|
171
|
+
|
|
172
|
+
## GUIDELINES
|
|
173
|
+
|
|
174
|
+
- Be thorough in analysis
|
|
175
|
+
- Use only labels from the provided list
|
|
176
|
+
- Extract info from issue template fields
|
|
177
|
+
- ALWAYS post a mention comment (unless no clear owner)
|
|
178
|
+
- Keep comments professional and brief
|
|
179
|
+
- Output reasoning to logs
|
|
180
|
+
|
|
181
|
+
**Start the triage process now.**
|
|
182
|
+
EOF
|
|
183
|
+
|
|
184
|
+
- name: Run Claude Code for Issue Triage
|
|
185
|
+
uses: anthropics/claude-code-base-action@beta
|
|
186
|
+
with:
|
|
187
|
+
prompt_file: /tmp/claude-prompts/triage-prompt.md
|
|
188
|
+
allowed_tools: "Bash(gh *),Read"
|
|
189
|
+
timeout_minutes: "5"
|
|
190
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
191
|
+
claude_env: |
|
|
192
|
+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
193
|
+
|
|
194
|
+
- name: Remove trigger label
|
|
195
|
+
if: github.event.action == 'labeled' && github.event.label.name == 'trigger:triage'
|
|
196
|
+
run: |
|
|
197
|
+
gh issue edit ${{ github.event.issue.number }} --remove-label "trigger:triage"
|
|
198
|
+
env:
|
|
199
|
+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
@@ -18,8 +18,8 @@ env:
|
|
|
18
18
|
jobs:
|
|
19
19
|
test:
|
|
20
20
|
name: Code quality check
|
|
21
|
-
# 添加 PR label 触发条件,只有添加了
|
|
22
|
-
if: contains(github.event.pull_request.labels.*.name, '
|
|
21
|
+
# 添加 PR label 触发条件,只有添加了 trigger:build-desktop 标签的 PR 才会触发构建
|
|
22
|
+
if: contains(github.event.pull_request.labels.*.name, 'trigger:build-desktop')
|
|
23
23
|
runs-on: ubuntu-latest # 只在 ubuntu 上运行一次检查
|
|
24
24
|
steps:
|
|
25
25
|
- name: Checkout base
|
|
@@ -51,7 +51,7 @@ jobs:
|
|
|
51
51
|
version:
|
|
52
52
|
name: Determine version
|
|
53
53
|
# 与 test job 相同的触发条件
|
|
54
|
-
if: contains(github.event.pull_request.labels.*.name, '
|
|
54
|
+
if: contains(github.event.pull_request.labels.*.name, 'trigger:build-desktop')
|
|
55
55
|
runs-on: ubuntu-latest
|
|
56
56
|
outputs:
|
|
57
57
|
# 输出版本信息,供后续 job 使用
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
# 添加 PR label 触发条件
|
|
23
23
|
if: |
|
|
24
24
|
(github.event_name == 'pull_request' &&
|
|
25
|
-
contains(github.event.pull_request.labels.*.name, '
|
|
25
|
+
contains(github.event.pull_request.labels.*.name, 'trigger:build-docker')) ||
|
|
26
26
|
github.event_name != 'pull_request'
|
|
27
27
|
|
|
28
28
|
strategy:
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
# 添加 PR label 触发条件
|
|
23
23
|
if: |
|
|
24
24
|
(github.event_name == 'pull_request' &&
|
|
25
|
-
contains(github.event.pull_request.labels.*.name, '
|
|
25
|
+
contains(github.event.pull_request.labels.*.name, 'trigger:build-docker')) ||
|
|
26
26
|
github.event_name != 'pull_request'
|
|
27
27
|
|
|
28
28
|
strategy:
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
# 添加 PR label 触发条件
|
|
23
23
|
if: |
|
|
24
24
|
(github.event_name == 'pull_request' &&
|
|
25
|
-
contains(github.event.pull_request.labels.*.name, '
|
|
25
|
+
contains(github.event.pull_request.labels.*.name, 'trigger:build-docker')) ||
|
|
26
26
|
github.event_name != 'pull_request'
|
|
27
27
|
|
|
28
28
|
strategy:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Auto-close duplicate issues
|
|
2
|
+
description: Auto-closes issues that are duplicates of existing issues
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 2 * * *"
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
auto-close-duplicates:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 10
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
issues: write
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout repository
|
|
18
|
+
uses: actions/checkout@v5
|
|
19
|
+
|
|
20
|
+
- name: Setup Bun
|
|
21
|
+
uses: oven-sh/setup-bun@v2
|
|
22
|
+
with:
|
|
23
|
+
bun-version: latest
|
|
24
|
+
|
|
25
|
+
- name: Auto-close duplicate issues
|
|
26
|
+
run: bun run .github/scripts/auto-close-duplicates.ts
|
|
27
|
+
env:
|
|
28
|
+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
29
|
+
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
|
|
30
|
+
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
|
|
@@ -15,7 +15,7 @@ permissions: read-all
|
|
|
15
15
|
jobs:
|
|
16
16
|
test:
|
|
17
17
|
name: Code quality check
|
|
18
|
-
# 添加 PR label 触发条件,只有添加了
|
|
18
|
+
# 添加 PR label 触发条件,只有添加了 trigger:build-desktop 标签的 PR 才会触发构建
|
|
19
19
|
runs-on: ubuntu-latest # 只在 ubuntu 上运行一次检查
|
|
20
20
|
steps:
|
|
21
21
|
- name: Checkout base
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.137.6](https://github.com/lobehub/lobe-chat/compare/v1.137.5...v1.137.6)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-10-14**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Update Claude workflows to use oauth token, vertext ai create image.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Update Claude workflows to use oauth token, closes [#9711](https://github.com/lobehub/lobe-chat/issues/9711) ([8dcb00e](https://github.com/lobehub/lobe-chat/commit/8dcb00e))
|
|
21
|
+
- **misc**: Vertext ai create image, closes [#9710](https://github.com/lobehub/lobe-chat/issues/9710) ([790d8fd](https://github.com/lobehub/lobe-chat/commit/790d8fd))
|
|
22
|
+
|
|
23
|
+
</details>
|
|
24
|
+
|
|
25
|
+
<div align="right">
|
|
26
|
+
|
|
27
|
+
[](#readme-top)
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
### [Version 1.137.5](https://github.com/lobehub/lobe-chat/compare/v1.137.4...v1.137.5)
|
|
32
|
+
|
|
33
|
+
<sup>Released on **2025-10-14**</sup>
|
|
34
|
+
|
|
35
|
+
#### 💄 Styles
|
|
36
|
+
|
|
37
|
+
- **misc**: Add imagen model to vertex ai.
|
|
38
|
+
|
|
39
|
+
<br/>
|
|
40
|
+
|
|
41
|
+
<details>
|
|
42
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
43
|
+
|
|
44
|
+
#### Styles
|
|
45
|
+
|
|
46
|
+
- **misc**: Add imagen model to vertex ai, closes [#9699](https://github.com/lobehub/lobe-chat/issues/9699) ([3b2a2c1](https://github.com/lobehub/lobe-chat/commit/3b2a2c1))
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
<div align="right">
|
|
51
|
+
|
|
52
|
+
[](#readme-top)
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
|
|
5
56
|
### [Version 1.137.4](https://github.com/lobehub/lobe-chat/compare/v1.137.3...v1.137.4)
|
|
6
57
|
|
|
7
58
|
<sup>Released on **2025-10-14**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Update Claude workflows to use oauth token, vertext ai create image."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-10-14",
|
|
9
|
+
"version": "1.137.6"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"improvements": [
|
|
14
|
+
"Add imagen model to vertex ai."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2025-10-14",
|
|
18
|
+
"version": "1.137.5"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {
|
|
4
22
|
"fixes": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.137.
|
|
3
|
+
"version": "1.137.6",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { filesPrompts } from '@lobechat/prompts';
|
|
2
|
-
import { imageUrlToBase64
|
|
2
|
+
import { imageUrlToBase64 } from '@lobechat/utils/imageToBase64';
|
|
3
|
+
import { parseDataUri } from '@lobechat/utils/uriParser';
|
|
4
|
+
import { isDesktopLocalStaticServerUrl } from '@lobechat/utils/url';
|
|
3
5
|
import debug from 'debug';
|
|
4
6
|
|
|
5
7
|
import { BaseProcessor } from '../base/BaseProcessor';
|
|
@@ -277,7 +279,7 @@ export class MessageContentProcessor extends BaseProcessor {
|
|
|
277
279
|
const { type } = parseDataUri(image.url);
|
|
278
280
|
|
|
279
281
|
let processedUrl = image.url;
|
|
280
|
-
if (type === 'url' &&
|
|
282
|
+
if (type === 'url' && isDesktopLocalStaticServerUrl(image.url)) {
|
|
281
283
|
const { base64, mimeType } = await imageUrlToBase64(image.url);
|
|
282
284
|
processedUrl = `data:${mimeType};base64,${base64}`;
|
|
283
285
|
}
|