Files
Jeffery (jiantw83)andClaude Sonnet 5.5 d9e50d196b feat: W7 功能標籤分類、對白檢索與注入 (#8)
用 $.model.complete(Haiku)判斷回應的功能標籤,從角色索引取同標籤對白,
以只增不改的訊息附在使用者訊息之前;失敗一律退回不注入。

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 17:44:09 +00:00

52 lines
1.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { FUNCTIONS, isFunctionTag, type FunctionTag } from './tags'
export const CLASSIFY_TIMEOUT_MS = 3000
// 判斷的是「角色接下來最自然的回應」屬於哪種功能,不是使用者這句話本身的功能。
export function buildClassifyPrompt(userText: string): string {
const choices = Object.entries(FUNCTIONS)
.filter(([key]) => key !== 'other')
.map(([key, label]) => `${key}:${label}`)
.join('\n')
return [
'使用者正在請助理協助做事。判斷在他這句話之後,一位親切的角色最自然的第一句回應屬於下列哪一種功能。',
'只回答功能代號一個詞,不要解釋;都不適合就回答 other。',
'',
choices,
'',
'<使用者的話>',
userText.slice(0, 600),
'</使用者的話>',
].join('\n')
}
// 只認回覆開頭的第一個詞,且必須在白名單內;其餘一律視為判斷失敗。
export function parseFunction(reply: string): FunctionTag | null {
const word = reply.trim().toLowerCase().match(/^[a-z_]+/)?.[0]
return isFunctionTag(word) ? word : null
}
export type Complete = (request: {
model: string
prompt: string
maxTokens: number
effort: 'low'
timeoutMs: number
}) => Promise<{ isAnswered: boolean; text?: string }>
// 任何失敗(逾時、API 錯誤、空回覆、白名單外)都回傳 null,由呼叫端退回不注入。
export async function classify(complete: Complete, userText: string): Promise<FunctionTag | null> {
try {
const r = await complete({
model: 'haiku',
prompt: buildClassifyPrompt(userText),
maxTokens: 16,
effort: 'low',
timeoutMs: CLASSIFY_TIMEOUT_MS,
})
return r.isAnswered && r.text ? parseFunction(r.text) : null
} catch {
return null
}
}