haixunMaster/haixun-backend/web/src/lib/islander/buildIslanderContext.ts

71 lines
2.5 KiB
TypeScript
Raw Normal View History

2026-06-23 16:55:10 +00:00
import type { ThreadsAccountData } from '../../types/api'
import type { OnboardingSnapshot } from '../onboarding'
import { formatSiteNavGuide } from './siteGuide'
import { resolveIslanderPageMeta } from './pageRegistry'
import { threadsAccountLabel } from '../threadsAccount'
import type { IslanderPageMeta } from './types'
type BuildContextInput = {
pathname: string
activeAccount: ThreadsAccountData | null
onboarding: OnboardingSnapshot
pageSnapshot?: string
pageMeta?: IslanderPageMeta | null
/** 僅在使用者主動問頁面/操作,或 agent 執行 action 後為 true */
includePageDetail?: boolean
}
const onboardingStepLabel = {
account: '建立經營帳號',
connection: '完成 Threads 連線',
persona: '建立至少一個人設',
} as const
export function buildIslanderContext(input: BuildContextInput): string {
const includePage = input.includePageDetail === true
const page = resolveIslanderPageMeta(input.pathname, input.pageMeta)
const accountLabel = input.activeAccount ? threadsAccountLabel(input.activeAccount) : '(尚未選擇)'
const publishPath = input.activeAccount
? `/threads/${input.activeAccount.id}/publish`
: '/settings'
const connectionsPath = input.activeAccount
? `/threads/${input.activeAccount.id}/connections`
: '/settings'
const sections = [
'【目前位置】',
`- 路徑:${input.pathname}`,
includePage
? `- 頁面:${page.title}`
: '- 頁面細節:使用者尚未詢問,請勿主動介紹這頁功能或元素',
'',
'【目前帳號】',
`- 經營帳號:${accountLabel}`,
`- 入門進度:${input.onboarding.isComplete ? '已完成' : input.onboarding.nextStep ? `進行中(${onboardingStepLabel[input.onboarding.nextStep]}` : '載入中'}`,
'',
'【常用捷徑】',
`- 設定與 AI key → /settings`,
`- 任務列表 → /jobs`,
`- 人設庫 → /personas`,
`- 發文 → ${publishPath}`,
`- 連線細節 → ${connectionsPath}`,
'',
'【站內導覽】',
formatSiteNavGuide(),
]
if (includePage) {
sections.push(
'',
'【目前頁面】',
page.purpose ? `- 用途:${page.purpose}` : '',
page.hints?.length ? `- 提示:${page.hints.join('')}` : '',
'',
'【目前頁面可互動元素】',
'格式ref | kind | label | metaoffscreen 表示需先 scroll',
input.pageSnapshot?.trim() || '(尚未擷取)',
)
}
return sections.filter((line) => line !== '').join('\n')
}