MCPcopy Index your code
hub / github.com/ChatLab/ChatLab / handler

Function handler

packages/tools/src/definitions/retrieve-chat-evidence.ts:338–453  ·  view source on GitHub ↗
(params: Record<string, unknown>, context: ToolExecutionContext)

Source from the content-addressed store, hash-verified

336}
337
338async function handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult> {
339 const locale = context.locale
340 const query = typeof params.query === 'string' ? params.query.trim() : ''
341 const criteria = typeof params.criteria === 'string' && params.criteria.trim() ? params.criteria.trim() : undefined
342 const keywords = Array.isArray(params.keywords)
343 ? (params.keywords.filter((k) => typeof k === 'string' && k.trim()) as string[])
344 : []
345 const requestedMode: EvidenceRetrievalMode =
346 params.mode === 'hybrid' || params.mode === 'semantic' || params.mode === 'keyword' || params.mode === 'auto'
347 ? params.mode
348 : 'auto'
349
350 const service = context.semanticIndexService
351 const semanticAvailable = !!service && (await service.canSearch(context.sessionId))
352 const rangeMs = parseEvidenceTimeRange(params, context)
353
354 const { mode, warnings } = resolveMode(requestedMode, semanticAvailable, keywords.length > 0)
355 if (!criteria) warnings.add('criteria_missing')
356
357 const runSemantic = mode === 'semantic' || mode === 'hybrid'
358 const runKeyword = mode === 'keyword' || mode === 'hybrid'
359
360 let semanticRan = false
361 let keywordRan = false
362 const semanticCandidates: EvidenceCandidate[] = []
363 let keywordCandidates: EvidenceCandidate[] = []
364
365 // 语义路径:service 内按 chunk 时间范围过滤;工具层再按 startTime/endTime 兜底过滤
366 if (runSemantic) {
367 if (!service || !semanticAvailable) {
368 warnings.add('semantic_unavailable')
369 } else {
370 const result = await service.searchForTool(context.sessionId, query, {
371 maxResults: clampMaxResults(params.max_results),
372 preprocessConfig: context.preprocessConfig,
373 ownerPlatformId: context.ownerPlatformId,
374 locale,
375 maxResultTokens: context.maxToolResultTokens,
376 timeFilter: rangeMs,
377 })
378 semanticRan = true
379 if (!result.available) {
380 warnings.add('semantic_unavailable')
381 } else {
382 if (result.partial) warnings.add('semantic_partial')
383 for (const s of result.sources) {
384 const startMs = parseIsoMs(s.startTime)
385 const endMs = parseIsoMs(s.endTime) ?? startMs
386 if (rangeMs && startMs != null && endMs != null && !overlapsTimeRangeMs(startMs, endMs, rangeMs)) continue
387 const evidenceText = stripLineTimestamps(s.text || s.snippet)
388 semanticCandidates.push({
389 messageId: s.startMessageId,
390 startMessageId: s.startMessageId,
391 endMessageId: s.endMessageId,
392 timestamp: startMs ?? 0,
393 rangeStartMs: startMs ?? 0,
394 rangeEndMs: endMs ?? startMs ?? 0,
395 snippet: evidenceText,

Callers

nothing calls this directly

Calls 15

parseEvidenceTimeRangeFunction · 0.85
resolveModeFunction · 0.85
clampMaxResultsFunction · 0.85
parseIsoMsFunction · 0.85
stripLineTimestampsFunction · 0.85
toKeywordTimeFilterFunction · 0.85
mergeCandidatesFunction · 0.85
buildGroupsFunction · 0.85
computeStatusFunction · 0.85
overlapsTimeRangeMsFunction · 0.70
isChineseFunction · 0.70

Tested by

no test coverage detected