@shareai-lab/kode 1.0.71 → 1.0.73
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 +142 -1
- package/README.zh-CN.md +47 -1
- package/package.json +5 -1
- package/src/ProjectOnboarding.tsx +47 -29
- package/src/Tool.ts +33 -4
- package/src/commands/agents.tsx +3401 -0
- package/src/commands/help.tsx +2 -2
- package/src/commands/resume.tsx +2 -1
- package/src/commands/terminalSetup.ts +4 -4
- package/src/commands.ts +3 -0
- package/src/components/ApproveApiKey.tsx +1 -1
- package/src/components/Config.tsx +10 -6
- package/src/components/ConsoleOAuthFlow.tsx +5 -4
- package/src/components/CustomSelect/select-option.tsx +28 -2
- package/src/components/CustomSelect/select.tsx +14 -5
- package/src/components/CustomSelect/theme.ts +45 -0
- package/src/components/Help.tsx +4 -4
- package/src/components/InvalidConfigDialog.tsx +1 -1
- package/src/components/LogSelector.tsx +1 -1
- package/src/components/MCPServerApprovalDialog.tsx +1 -1
- package/src/components/Message.tsx +2 -0
- package/src/components/ModelListManager.tsx +10 -6
- package/src/components/ModelSelector.tsx +201 -23
- package/src/components/ModelStatusDisplay.tsx +7 -5
- package/src/components/PromptInput.tsx +117 -87
- package/src/components/SentryErrorBoundary.ts +3 -3
- package/src/components/StickerRequestForm.tsx +16 -0
- package/src/components/StructuredDiff.tsx +36 -29
- package/src/components/TextInput.tsx +13 -0
- package/src/components/TodoItem.tsx +11 -0
- package/src/components/TrustDialog.tsx +1 -1
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +5 -1
- package/src/components/messages/AssistantToolUseMessage.tsx +14 -4
- package/src/components/messages/TaskProgressMessage.tsx +32 -0
- package/src/components/messages/TaskToolMessage.tsx +58 -0
- package/src/components/permissions/FallbackPermissionRequest.tsx +2 -4
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +1 -1
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +5 -3
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +1 -1
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +5 -3
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +2 -4
- package/src/components/permissions/PermissionRequest.tsx +3 -5
- package/src/constants/macros.ts +2 -0
- package/src/constants/modelCapabilities.ts +179 -0
- package/src/constants/models.ts +90 -0
- package/src/constants/product.ts +1 -1
- package/src/context.ts +7 -7
- package/src/entrypoints/cli.tsx +23 -3
- package/src/entrypoints/mcp.ts +10 -10
- package/src/hooks/useCanUseTool.ts +1 -1
- package/src/hooks/useTextInput.ts +5 -2
- package/src/hooks/useUnifiedCompletion.ts +1404 -0
- package/src/messages.ts +1 -0
- package/src/query.ts +3 -0
- package/src/screens/ConfigureNpmPrefix.tsx +1 -1
- package/src/screens/Doctor.tsx +1 -1
- package/src/screens/REPL.tsx +15 -9
- package/src/services/adapters/base.ts +38 -0
- package/src/services/adapters/chatCompletions.ts +90 -0
- package/src/services/adapters/responsesAPI.ts +170 -0
- package/src/services/claude.ts +198 -62
- package/src/services/customCommands.ts +43 -22
- package/src/services/gpt5ConnectionTest.ts +340 -0
- package/src/services/mcpClient.ts +1 -1
- package/src/services/mentionProcessor.ts +273 -0
- package/src/services/modelAdapterFactory.ts +69 -0
- package/src/services/openai.ts +521 -12
- package/src/services/responseStateManager.ts +90 -0
- package/src/services/systemReminder.ts +113 -12
- package/src/test/testAdapters.ts +96 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +120 -56
- package/src/tools/BashTool/BashTool.tsx +4 -31
- package/src/tools/BashTool/BashToolResultMessage.tsx +1 -1
- package/src/tools/BashTool/OutputLine.tsx +1 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +4 -5
- package/src/tools/FileReadTool/FileReadTool.tsx +43 -10
- package/src/tools/MCPTool/MCPTool.tsx +2 -1
- package/src/tools/MultiEditTool/MultiEditTool.tsx +2 -2
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +15 -23
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +1 -1
- package/src/tools/TaskTool/TaskTool.tsx +170 -86
- package/src/tools/TaskTool/prompt.ts +61 -25
- package/src/tools/ThinkTool/ThinkTool.tsx +1 -3
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +11 -10
- package/src/tools/lsTool/lsTool.tsx +5 -2
- package/src/tools.ts +16 -16
- package/src/types/conversation.ts +51 -0
- package/src/types/logs.ts +58 -0
- package/src/types/modelCapabilities.ts +64 -0
- package/src/types/notebook.ts +87 -0
- package/src/utils/advancedFuzzyMatcher.ts +290 -0
- package/src/utils/agentLoader.ts +284 -0
- package/src/utils/ask.tsx +1 -0
- package/src/utils/commands.ts +1 -1
- package/src/utils/commonUnixCommands.ts +161 -0
- package/src/utils/config.ts +173 -2
- package/src/utils/conversationRecovery.ts +1 -0
- package/src/utils/debugLogger.ts +13 -13
- package/src/utils/exampleCommands.ts +1 -0
- package/src/utils/fuzzyMatcher.ts +328 -0
- package/src/utils/messages.tsx +6 -5
- package/src/utils/responseState.ts +23 -0
- package/src/utils/secureFile.ts +559 -0
- package/src/utils/terminal.ts +1 -0
- package/src/utils/theme.ts +11 -0
- package/src/hooks/useSlashCommandTypeahead.ts +0 -137
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Method Inspired Fuzzy Matching Algorithm
|
|
3
|
+
*
|
|
4
|
+
* Multi-algorithm weighted scoring system inspired by:
|
|
5
|
+
* - Sogou/Baidu Pinyin input method algorithms
|
|
6
|
+
* - Double-pinyin abbreviation matching
|
|
7
|
+
* - Terminal completion best practices (fzf, zsh, fish)
|
|
8
|
+
*
|
|
9
|
+
* Designed specifically for command/terminal completion scenarios
|
|
10
|
+
* where users type abbreviations like "nde" expecting "node"
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface MatchResult {
|
|
14
|
+
score: number
|
|
15
|
+
algorithm: string // Which algorithm contributed most to the score
|
|
16
|
+
confidence: number // 0-1 confidence level
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FuzzyMatcherConfig {
|
|
20
|
+
// Algorithm weights (must sum to 1.0)
|
|
21
|
+
weights: {
|
|
22
|
+
prefix: number // Direct prefix matching ("nod" → "node")
|
|
23
|
+
substring: number // Substring matching ("ode" → "node")
|
|
24
|
+
abbreviation: number // Key chars matching ("nde" → "node")
|
|
25
|
+
editDistance: number // Typo tolerance ("noda" → "node")
|
|
26
|
+
popularity: number // Common command boost
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Scoring parameters
|
|
30
|
+
minScore: number // Minimum score threshold
|
|
31
|
+
maxEditDistance: number // Maximum edits allowed
|
|
32
|
+
popularCommands: string[] // Commands to boost
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const DEFAULT_CONFIG: FuzzyMatcherConfig = {
|
|
36
|
+
weights: {
|
|
37
|
+
prefix: 0.35, // Strong weight for prefix matching
|
|
38
|
+
substring: 0.20, // Good for partial matches
|
|
39
|
+
abbreviation: 0.30, // Key for "nde"→"node" cases
|
|
40
|
+
editDistance: 0.10, // Typo tolerance
|
|
41
|
+
popularity: 0.05 // Slight bias for common commands
|
|
42
|
+
},
|
|
43
|
+
minScore: 10, // Lower threshold for better matching
|
|
44
|
+
maxEditDistance: 2,
|
|
45
|
+
popularCommands: [
|
|
46
|
+
'node', 'npm', 'git', 'ls', 'cd', 'cat', 'grep', 'find', 'cp', 'mv',
|
|
47
|
+
'python', 'java', 'docker', 'curl', 'wget', 'vim', 'nano'
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class FuzzyMatcher {
|
|
52
|
+
private config: FuzzyMatcherConfig
|
|
53
|
+
|
|
54
|
+
constructor(config: Partial<FuzzyMatcherConfig> = {}) {
|
|
55
|
+
this.config = { ...DEFAULT_CONFIG, ...config }
|
|
56
|
+
|
|
57
|
+
// Normalize weights to sum to 1.0
|
|
58
|
+
const weightSum = Object.values(this.config.weights).reduce((a, b) => a + b, 0)
|
|
59
|
+
if (Math.abs(weightSum - 1.0) > 0.01) {
|
|
60
|
+
Object.keys(this.config.weights).forEach(key => {
|
|
61
|
+
this.config.weights[key as keyof typeof this.config.weights] /= weightSum
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Calculate fuzzy match score for a candidate against a query
|
|
68
|
+
*/
|
|
69
|
+
match(candidate: string, query: string): MatchResult {
|
|
70
|
+
const text = candidate.toLowerCase()
|
|
71
|
+
const pattern = query.toLowerCase()
|
|
72
|
+
|
|
73
|
+
// Quick perfect match exits
|
|
74
|
+
if (text === pattern) {
|
|
75
|
+
return { score: 1000, algorithm: 'exact', confidence: 1.0 }
|
|
76
|
+
}
|
|
77
|
+
if (text.startsWith(pattern)) {
|
|
78
|
+
return {
|
|
79
|
+
score: 900 + (10 - pattern.length),
|
|
80
|
+
algorithm: 'prefix-exact',
|
|
81
|
+
confidence: 0.95
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Run all algorithms
|
|
86
|
+
const scores = {
|
|
87
|
+
prefix: this.prefixScore(text, pattern),
|
|
88
|
+
substring: this.substringScore(text, pattern),
|
|
89
|
+
abbreviation: this.abbreviationScore(text, pattern),
|
|
90
|
+
editDistance: this.editDistanceScore(text, pattern),
|
|
91
|
+
popularity: this.popularityScore(text)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Weighted combination
|
|
95
|
+
const rawScore = Object.entries(scores).reduce((total, [algorithm, score]) => {
|
|
96
|
+
const weight = this.config.weights[algorithm as keyof typeof this.config.weights]
|
|
97
|
+
return total + (score * weight)
|
|
98
|
+
}, 0)
|
|
99
|
+
|
|
100
|
+
// Length penalty (prefer shorter commands)
|
|
101
|
+
const lengthPenalty = Math.max(0, text.length - 6) * 1.5
|
|
102
|
+
const finalScore = Math.max(0, rawScore - lengthPenalty)
|
|
103
|
+
|
|
104
|
+
// Determine primary algorithm and confidence
|
|
105
|
+
const maxAlgorithm = Object.entries(scores).reduce((max, [alg, score]) =>
|
|
106
|
+
score > max.score ? { algorithm: alg, score } : max,
|
|
107
|
+
{ algorithm: 'none', score: 0 }
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const confidence = Math.min(1.0, finalScore / 100)
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
score: finalScore,
|
|
114
|
+
algorithm: maxAlgorithm.algorithm,
|
|
115
|
+
confidence
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Algorithm 1: Prefix Matching (like pinyin prefix)
|
|
121
|
+
* Handles cases like "nod" → "node"
|
|
122
|
+
*/
|
|
123
|
+
private prefixScore(text: string, pattern: string): number {
|
|
124
|
+
if (!text.startsWith(pattern)) return 0
|
|
125
|
+
|
|
126
|
+
// Score based on prefix length vs total length
|
|
127
|
+
const coverage = pattern.length / text.length
|
|
128
|
+
return 100 * coverage
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Algorithm 2: Substring Matching (like pinyin contains)
|
|
133
|
+
* Handles cases like "ode" → "node", "py3" → "python3"
|
|
134
|
+
*/
|
|
135
|
+
private substringScore(text: string, pattern: string): number {
|
|
136
|
+
// Direct substring match
|
|
137
|
+
const index = text.indexOf(pattern)
|
|
138
|
+
if (index !== -1) {
|
|
139
|
+
// Earlier position and better coverage = higher score
|
|
140
|
+
const positionFactor = Math.max(0, 10 - index) / 10
|
|
141
|
+
const coverageFactor = pattern.length / text.length
|
|
142
|
+
return 80 * positionFactor * coverageFactor
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Special handling for numeric suffixes (py3 → python3)
|
|
146
|
+
// Check if pattern ends with a number and try prefix match + number
|
|
147
|
+
const numMatch = pattern.match(/^(.+?)(\d+)$/)
|
|
148
|
+
if (numMatch) {
|
|
149
|
+
const [, prefix, num] = numMatch
|
|
150
|
+
// Check if text starts with prefix and ends with the same number
|
|
151
|
+
if (text.startsWith(prefix) && text.endsWith(num)) {
|
|
152
|
+
// Good match for patterns like "py3" → "python3"
|
|
153
|
+
const coverageFactor = pattern.length / text.length
|
|
154
|
+
return 70 * coverageFactor + 20 // Bonus for numeric suffix match
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return 0
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Algorithm 3: Abbreviation Matching (key innovation)
|
|
163
|
+
* Handles cases like "nde" → "node", "pyt3" → "python3", "gp5" → "gpt-5"
|
|
164
|
+
*/
|
|
165
|
+
private abbreviationScore(text: string, pattern: string): number {
|
|
166
|
+
let score = 0
|
|
167
|
+
let textPos = 0
|
|
168
|
+
let perfectStart = false
|
|
169
|
+
let consecutiveMatches = 0
|
|
170
|
+
let wordBoundaryMatches = 0
|
|
171
|
+
|
|
172
|
+
// Split text by hyphens to handle word boundaries better
|
|
173
|
+
const textWords = text.split('-')
|
|
174
|
+
const textClean = text.replace(/-/g, '').toLowerCase()
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
177
|
+
const char = pattern[i]
|
|
178
|
+
let charFound = false
|
|
179
|
+
|
|
180
|
+
// Try to find in clean text (no hyphens)
|
|
181
|
+
for (let j = textPos; j < textClean.length; j++) {
|
|
182
|
+
if (textClean[j] === char) {
|
|
183
|
+
charFound = true
|
|
184
|
+
|
|
185
|
+
// Check if this character is at a word boundary in original text
|
|
186
|
+
let originalPos = 0
|
|
187
|
+
let cleanPos = 0
|
|
188
|
+
for (let k = 0; k < text.length; k++) {
|
|
189
|
+
if (text[k] === '-') continue
|
|
190
|
+
if (cleanPos === j) {
|
|
191
|
+
originalPos = k
|
|
192
|
+
break
|
|
193
|
+
}
|
|
194
|
+
cleanPos++
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Consecutive character bonus
|
|
198
|
+
if (j === textPos) {
|
|
199
|
+
consecutiveMatches++
|
|
200
|
+
} else {
|
|
201
|
+
consecutiveMatches = 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Position-sensitive scoring
|
|
205
|
+
if (i === 0 && j === 0) {
|
|
206
|
+
score += 50 // Perfect first character
|
|
207
|
+
perfectStart = true
|
|
208
|
+
} else if (originalPos === 0 || text[originalPos - 1] === '-') {
|
|
209
|
+
score += 35 // Word boundary match
|
|
210
|
+
wordBoundaryMatches++
|
|
211
|
+
} else if (j <= 2) {
|
|
212
|
+
score += 20 // Early position
|
|
213
|
+
} else if (j <= 6) {
|
|
214
|
+
score += 10 // Mid position
|
|
215
|
+
} else {
|
|
216
|
+
score += 5 // Late position
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Consecutive character bonus
|
|
220
|
+
if (consecutiveMatches > 1) {
|
|
221
|
+
score += consecutiveMatches * 5
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
textPos = j + 1
|
|
225
|
+
break
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!charFound) return 0 // Invalid abbreviation
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Critical bonuses
|
|
233
|
+
if (perfectStart) score += 30
|
|
234
|
+
if (wordBoundaryMatches >= 2) score += 25 // Multiple word boundaries
|
|
235
|
+
if (textPos <= textClean.length * 0.8) score += 15 // Compact abbreviation
|
|
236
|
+
|
|
237
|
+
// Special bonus for number matching at end
|
|
238
|
+
const lastPatternChar = pattern[pattern.length - 1]
|
|
239
|
+
const lastTextChar = text[text.length - 1]
|
|
240
|
+
if (/\d/.test(lastPatternChar) && lastPatternChar === lastTextChar) {
|
|
241
|
+
score += 25
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return score
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Algorithm 4: Edit Distance (typo tolerance)
|
|
249
|
+
* Handles cases like "noda" → "node"
|
|
250
|
+
*/
|
|
251
|
+
private editDistanceScore(text: string, pattern: string): number {
|
|
252
|
+
if (pattern.length > text.length + this.config.maxEditDistance) return 0
|
|
253
|
+
|
|
254
|
+
// Simplified Levenshtein distance
|
|
255
|
+
const dp: number[][] = []
|
|
256
|
+
const m = pattern.length
|
|
257
|
+
const n = text.length
|
|
258
|
+
|
|
259
|
+
// Initialize DP table
|
|
260
|
+
for (let i = 0; i <= m; i++) {
|
|
261
|
+
dp[i] = []
|
|
262
|
+
for (let j = 0; j <= n; j++) {
|
|
263
|
+
if (i === 0) dp[i][j] = j
|
|
264
|
+
else if (j === 0) dp[i][j] = i
|
|
265
|
+
else {
|
|
266
|
+
const cost = pattern[i-1] === text[j-1] ? 0 : 1
|
|
267
|
+
dp[i][j] = Math.min(
|
|
268
|
+
dp[i-1][j] + 1, // deletion
|
|
269
|
+
dp[i][j-1] + 1, // insertion
|
|
270
|
+
dp[i-1][j-1] + cost // substitution
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const distance = dp[m][n]
|
|
277
|
+
if (distance > this.config.maxEditDistance) return 0
|
|
278
|
+
|
|
279
|
+
return Math.max(0, 30 - distance * 10)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Algorithm 5: Command Popularity (like frequency in input method)
|
|
284
|
+
* Boost common commands that users frequently type
|
|
285
|
+
*/
|
|
286
|
+
private popularityScore(text: string): number {
|
|
287
|
+
if (this.config.popularCommands.includes(text)) {
|
|
288
|
+
return 40
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Short commands are often more commonly used
|
|
292
|
+
if (text.length <= 5) return 10
|
|
293
|
+
|
|
294
|
+
return 0
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Batch match multiple candidates and return sorted results
|
|
299
|
+
*/
|
|
300
|
+
matchMany(candidates: string[], query: string): Array<{candidate: string, result: MatchResult}> {
|
|
301
|
+
return candidates
|
|
302
|
+
.map(candidate => ({
|
|
303
|
+
candidate,
|
|
304
|
+
result: this.match(candidate, query)
|
|
305
|
+
}))
|
|
306
|
+
.filter(item => item.result.score >= this.config.minScore)
|
|
307
|
+
.sort((a, b) => b.result.score - a.result.score)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Export convenience functions
|
|
312
|
+
export const defaultMatcher = new FuzzyMatcher()
|
|
313
|
+
|
|
314
|
+
export function matchCommand(command: string, query: string): MatchResult {
|
|
315
|
+
return defaultMatcher.match(command, query)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Import the advanced matcher
|
|
319
|
+
import { matchManyAdvanced } from './advancedFuzzyMatcher'
|
|
320
|
+
|
|
321
|
+
export function matchCommands(commands: string[], query: string): Array<{command: string, score: number}> {
|
|
322
|
+
// Use the advanced matcher for better results
|
|
323
|
+
return matchManyAdvanced(commands, query, 5) // Lower threshold for better matching
|
|
324
|
+
.map(item => ({
|
|
325
|
+
command: item.candidate,
|
|
326
|
+
score: item.score
|
|
327
|
+
}))
|
|
328
|
+
}
|
package/src/utils/messages.tsx
CHANGED
|
@@ -355,7 +355,7 @@ export async function processUserInput(
|
|
|
355
355
|
if (input.includes('!`') || input.includes('@')) {
|
|
356
356
|
try {
|
|
357
357
|
// Import functions from customCommands service to avoid code duplication
|
|
358
|
-
const { executeBashCommands
|
|
358
|
+
const { executeBashCommands } = await import(
|
|
359
359
|
'../services/customCommands'
|
|
360
360
|
)
|
|
361
361
|
|
|
@@ -366,11 +366,12 @@ export async function processUserInput(
|
|
|
366
366
|
processedInput = await executeBashCommands(processedInput)
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
//
|
|
369
|
+
// Process mentions for system reminder integration
|
|
370
|
+
// Note: We don't call resolveFileReferences here anymore -
|
|
371
|
+
// @file mentions should trigger Read tool usage via reminders, not embed content
|
|
370
372
|
if (input.includes('@')) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
processedInput = await resolveFileReferences(processedInput)
|
|
373
|
+
const { processMentions } = await import('../services/mentionProcessor')
|
|
374
|
+
await processMentions(input)
|
|
374
375
|
}
|
|
375
376
|
} catch (error) {
|
|
376
377
|
console.warn('Dynamic content processing failed:', error)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response state management for Responses API
|
|
3
|
+
* Tracks previous_response_id for conversation chaining
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Store the last response ID for each conversation
|
|
7
|
+
const responseIdCache = new Map<string, string>()
|
|
8
|
+
|
|
9
|
+
export function getLastResponseId(conversationId: string): string | undefined {
|
|
10
|
+
return responseIdCache.get(conversationId)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function setLastResponseId(conversationId: string, responseId: string): void {
|
|
14
|
+
responseIdCache.set(conversationId, responseId)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function clearResponseId(conversationId: string): void {
|
|
18
|
+
responseIdCache.delete(conversationId)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function clearAllResponseIds(): void {
|
|
22
|
+
responseIdCache.clear()
|
|
23
|
+
}
|