feat: W7 功能標籤分類、對白檢索與注入 (#8)
用 $.model.complete(Haiku)判斷回應的功能標籤,從角色索引取同標籤對白, 以只增不改的訊息附在使用者訊息之前;失敗一律退回不注入。 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
1c4e0c5d98
commit
d9e50d196b
@@ -0,0 +1,51 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user