@klarkxy/dsh-zhihu 0.1.9 → 0.2.0
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 +26 -22
- package/docs/README.zh-CN.md +26 -22
- package/lib/client.js +2012 -887
- package/lib/index.d.ts +1 -1
- package/lib/index.js +78 -103
- package/lib/index.js.map +1 -1
- package/lib/open-platform.js +8 -8
- package/lib/open-platform.js.map +1 -1
- package/lib/tools.js +11 -11
- package/lib/tools.js.map +1 -1
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +22 -15
package/lib/open-platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-platform.js","names":[],"sources":["../src/zhihu-client.ts","../src/search-api.ts","../src/operations.ts","../src/open-platform.ts"],"sourcesContent":["/**\n * 知乎开放平台共享请求层:Access Secret 解析、超时封装、信封解析与执行计量。\n *\n * 端点规范(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - Base URL: https://developer.zhihu.com\n * - 公共 Headers: Authorization: Bearer <access_secret>、X-Request-Timestamp、Accept\n * - 除直答外的 REST 接口返回 {Code, Message, Data} 信封,Code 非 0 表示业务错误。\n *\n * Token 解析顺序(按契约,**不**把 token 放进 schema 参数):\n * 1. 可选的 credential 解析器(应用设置界面写入 `ZHIHU_ACCESS_TOKEN` 后,\n * 通过 `ctx.credentials.resolve` 取回);命中即返回,source 标记为 `credential`。\n * 2. 环境变量 ZHIHU_ACCESS_TOKEN\n * 3. 环境变量 ZHIHU_ACCESS_SECRET(zhihu-search CLI 同名变量)\n * 4. ~/.config/zhihu-search/credentials.json 的 access_secret 字段\n * 都没有则抛出带中文配置指引的 TOKEN_MISSING。\n */\nimport { readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { ZhihuQuotaId } from './contracts.ts'\n\nexport const ZHIHU_BASE_URL = 'https://developer.zhihu.com'\nexport const ZHIHU_DEFAULT_TIMEOUT_MS = 15_000\nexport const ZHIHU_SUMMARY_MAX_CHARS = 200\n\nconst ZHIHU_CREDENTIALS_PRIMARY = 'ZHIHU_ACCESS_TOKEN'\nconst ZHIHU_CREDENTIALS_FALLBACK = 'ZHIHU_ACCESS_SECRET'\nconst ZHIHU_CREDENTIALS_FILE = join(homedir(), '.config', 'zhihu-search', 'credentials.json')\n\ntype TokenSource = 'credential' | 'env-primary' | 'env-fallback' | 'file'\n\nexport type ZhihuSearchToken = { token: string; source: TokenSource }\n\nexport type ZhihuSearchFetcher = (input: string, init?: { method?: string; headers?: Record<string, string>; body?: string | FormData; signal?: AbortSignal }) => Promise<{\n ok: boolean\n status: number\n headers?: { get(name: string): string | null }\n text(): Promise<string>\n json(): Promise<unknown>\n}>\n\nconst globalFetch: ZhihuSearchFetcher | undefined = typeof globalThis !== 'undefined' && typeof (globalThis as { fetch?: unknown }).fetch === 'function'\n ? (input, init) => {\n const f = (globalThis as { fetch: typeof globalThis.fetch }).fetch\n return f(input as Parameters<typeof f>[0], init as Parameters<typeof f>[1] | undefined) as unknown as ReturnType<ZhihuSearchFetcher>\n }\n : undefined\n\nfunction looksLikeToken(value: string): boolean {\n const trimmed = value.trim()\n return trimmed.length >= 8 && trimmed.length <= 256\n}\n\nasync function readCredentialsFile(path: string): Promise<string | undefined> {\n try {\n const raw = await readFile(path, 'utf8')\n const parsed = JSON.parse(raw) as { access_secret?: unknown } | null\n if (parsed && typeof parsed === 'object' && typeof parsed.access_secret === 'string' && looksLikeToken(parsed.access_secret)) {\n return parsed.access_secret.trim()\n }\n } catch {\n // 文件不存在或 JSON 解析失败都不算硬错误,让上层回退到 isError 提示\n }\n return undefined\n}\n\nexport type ZhihuSearchResolveOptions = {\n /** Resolve the Access Secret via host-managed credentials (e.g. the settings UI). */\n resolveCredential?: () => Promise<string | undefined>\n}\n\nexport async function resolveZhihuToken(\n env: NodeJS.ProcessEnv = process.env,\n options: ZhihuSearchResolveOptions = {},\n): Promise<ZhihuSearchToken> {\n if (options.resolveCredential) {\n const fromCredential = (await options.resolveCredential())?.trim()\n if (fromCredential && looksLikeToken(fromCredential)) {\n return { token: fromCredential, source: 'credential' }\n }\n }\n const primary = env[ZHIHU_CREDENTIALS_PRIMARY]?.trim()\n if (primary && looksLikeToken(primary)) return { token: primary, source: 'env-primary' }\n const fallback = env[ZHIHU_CREDENTIALS_FALLBACK]?.trim()\n if (fallback && looksLikeToken(fallback)) return { token: fallback, source: 'env-fallback' }\n const fromFile = await readCredentialsFile(ZHIHU_CREDENTIALS_FILE)\n if (fromFile) return { token: fromFile, source: 'file' }\n throw new ZhihuSearchError('TOKEN_MISSING', [\n '未找到知乎 Access Secret。请在「设置 → 知乎」中填写;',\n `也可设置环境变量 ${ZHIHU_CREDENTIALS_PRIMARY} 或写入 ~/.config/zhihu-search/credentials.json。`,\n ].join(''))\n}\n\nexport type ZhihuErrorDetails = {\n upstreamCode?: number\n retryAfter?: number\n retryable?: boolean\n}\n\nexport class ZhihuSearchError extends Error {\n readonly code: 'TOKEN_MISSING' | 'HTTP_ERROR' | 'TIMEOUT' | 'BAD_RESPONSE'\n | 'INVALID_ARGUMENTS' | 'TOKEN_INVALID' | 'RATE_LIMITED' | 'UPSTREAM_UNAVAILABLE' | 'CANCELLED'\n readonly status?: number\n readonly upstreamCode?: number\n readonly retryAfter?: number\n readonly retryable?: boolean\n constructor(code: ZhihuSearchError['code'], message: string, status?: number, details: ZhihuErrorDetails = {}) {\n super(message)\n this.name = 'ZhihuSearchError'\n this.code = code\n if (status !== undefined) this.status = status\n if (details.upstreamCode !== undefined) this.upstreamCode = details.upstreamCode\n if (details.retryAfter !== undefined) this.retryAfter = details.retryAfter\n if (details.retryable !== undefined) this.retryable = details.retryable\n }\n}\n\n/** Metering payload emitted after each zhihu tool execution. */\nexport type ZhihuSearchExecuted = { ok: boolean; results: number; quotaId?: ZhihuQuotaId }\n\n/** Metering must never break the tool itself. */\nexport function reportExecuted(hook: ((event: ZhihuSearchExecuted) => void) | undefined, event: ZhihuSearchExecuted): void {\n if (!hook) return\n try {\n hook(event)\n } catch {\n // Best-effort metering; swallow hook failures.\n }\n}\n\nexport type ZhihuClientOptions = ZhihuSearchResolveOptions & {\n fetcher?: ZhihuSearchFetcher\n /** Allows tests to bypass process env; defaults to process.env. */\n env?: NodeJS.ProcessEnv\n signal?: AbortSignal\n /** Override the request timeout in ms. Defaults to {@link ZHIHU_DEFAULT_TIMEOUT_MS}. */\n timeoutMs?: number\n}\n\nfunction isAbortError(error: unknown): boolean {\n if (error instanceof Error && error.name === 'AbortError') return true\n return typeof error === 'object' && error !== null && (error as { name?: unknown }).name === 'AbortError'\n}\n\n/** Parse Retry-After seconds or an HTTP date; never invent a quota reset time. */\nexport function parseZhihuRetryAfter(value: string | null | undefined, now = Date.now()): number | undefined {\n if (!value?.trim()) return undefined\n const text = value.trim()\n if (/^\\d+(?:\\.\\d+)?$/.test(text)) {\n const seconds = Number(text)\n return Number.isFinite(seconds) ? Math.ceil(seconds) : undefined\n }\n // Do not let Date.parse interpret negative numbers as calendar dates.\n if (!/[a-z]/i.test(text)) return undefined\n const date = Date.parse(text)\n return Number.isFinite(date) ? Math.max(0, Math.ceil((date - now) / 1000)) : undefined\n}\n\n/**\n * Shared authenticated request. envelope=true opts into official error semantics\n * and returns Data. Legacy callers still receive the full JSON / chat response.\n * The timeout and cancellation cover BOTH headers and response-body consumption.\n * No requests are retried, including 429, exhausted quota, or risk-control denial.\n */\nexport async function zhihuFetchJson(\n path: string,\n init: { method?: 'GET' | 'POST'; params?: Record<string, string>; body?: unknown; formData?: FormData; envelope?: boolean },\n label: string,\n options: ZhihuClientOptions = {},\n): Promise<unknown> {\n const linked = options.signal\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n const url = new URL(path, ZHIHU_BASE_URL)\n if (url.origin !== ZHIHU_BASE_URL || url.username || url.password) {\n throw new ZhihuSearchError('INVALID_ARGUMENTS', '只允许请求知乎开放平台。')\n }\n for (const [key, value] of Object.entries(init.params ?? {})) url.searchParams.set(key, value)\n const token = await resolveZhihuToken(options.env, { resolveCredential: options.resolveCredential })\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n const fetcher = options.fetcher ?? globalFetch\n if (!fetcher) throw new ZhihuSearchError('BAD_RESPONSE', '当前环境没有可用的 fetch。')\n const method = init.method ?? (init.formData || init.body !== undefined ? 'POST' : 'GET')\n const timeout = options.timeoutMs !== undefined && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0\n ? options.timeoutMs : ZHIHU_DEFAULT_TIMEOUT_MS\n const controller = new AbortController()\n const onAbort = () => controller.abort(linked?.reason)\n if (linked?.aborted) onAbort()\n else linked?.addEventListener('abort', onAbort, { once: true })\n const timer = setTimeout(() => controller.abort(new Error('zhihu request timeout')), timeout)\n let stopWaiting = () => {}\n const aborted = new Promise<never>((_resolve, reject) => {\n const rejectAbort = () => reject(controller.signal.reason)\n if (controller.signal.aborted) rejectAbort()\n else {\n controller.signal.addEventListener('abort', rejectAbort, { once: true })\n stopWaiting = () => controller.signal.removeEventListener('abort', rejectAbort)\n }\n })\n try {\n const request = async () => {\n controller.signal.throwIfAborted()\n const response = await fetcher(url.toString(), {\n method,\n headers: {\n Authorization: `Bearer ${token.token}`,\n 'X-Request-Timestamp': String(Math.floor(Date.now() / 1000)),\n Accept: 'application/json',\n // Let fetch supply the multipart boundary.\n ...(method === 'POST' && !init.formData ? { 'Content-Type': 'application/json' } : {}),\n },\n signal: controller.signal,\n ...(init.formData ? { body: init.formData } : init.body !== undefined ? { body: JSON.stringify(init.body) } : {}),\n })\n const retryAfter = parseZhihuRetryAfter(response.headers?.get('Retry-After'))\n const httpError = () => {\n const code = response.status === 429 ? 'RATE_LIMITED'\n : init.envelope && (response.status === 401 || response.status === 403) ? 'TOKEN_INVALID'\n : 'HTTP_ERROR'\n return new ZhihuSearchError(code, `${label}返回 HTTP ${response.status}。`, response.status,\n code === 'RATE_LIMITED' ? { retryAfter, retryable: true } : {})\n }\n let body: unknown\n try { body = await response.json() }\n catch (error) {\n if (controller.signal.aborted) throw error\n if (!response.ok) throw httpError()\n throw new ZhihuSearchError('BAD_RESPONSE', `${label}响应不是合法 JSON。`)\n }\n controller.signal.throwIfAborted()\n // A business error remains meaningful even when the HTTP status is 400.\n const isEnvelope = body !== null && typeof body === 'object' && !Array.isArray(body) && 'Code' in body\n if (!response.ok && !isEnvelope) throw httpError()\n if (init.envelope || (isEnvelope && (body as { Code: unknown }).Code !== 0 && (body as { Code: unknown }).Code !== '0')) {\n const data = parseZhihuEnvelope(body, { status: response.status, retryAfter, officialErrors: init.envelope })\n if (!response.ok) throw httpError()\n if (init.envelope) return data\n }\n if (!response.ok) throw httpError()\n return body\n }\n return await Promise.race([request(), aborted])\n } catch (error) {\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n if (controller.signal.aborted || isAbortError(error)) {\n throw new ZhihuSearchError('TIMEOUT', `${label}超时(${Math.round(timeout / 1000)} 秒),请稍后再试。`)\n }\n if (error instanceof ZhihuSearchError) {\n error.message = error.message.replaceAll(token.token, '[REDACTED]')\n throw error\n }\n const message = (error instanceof Error ? error.message : String(error)).replaceAll(token.token, '[REDACTED]')\n throw new ZhihuSearchError('BAD_RESPONSE', `${label}失败:${message}`)\n } finally {\n clearTimeout(timer)\n stopWaiting()\n linked?.removeEventListener('abort', onAbort)\n }\n}\n\nconst ZHIHU_BUSINESS_ERRORS: Record<number, ZhihuSearchError['code']> = {\n 10001: 'INVALID_ARGUMENTS', 20001: 'TOKEN_INVALID',\n 30001: 'RATE_LIMITED', 30002: 'RATE_LIMITED',\n 40001: 'INVALID_ARGUMENTS', 40002: 'INVALID_ARGUMENTS', 40003: 'RATE_LIMITED',\n 40004: 'INVALID_ARGUMENTS', 40005: 'INVALID_ARGUMENTS', 40006: 'INVALID_ARGUMENTS',\n 50002: 'UPSTREAM_UNAVAILABLE', 90001: 'UPSTREAM_UNAVAILABLE',\n}\n\n/** Parse the official envelope without coercing null/false/empty Code into success. */\nexport function parseZhihuEnvelope(body: unknown, meta: { status?: number; retryAfter?: number; officialErrors?: boolean } = {}): unknown {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎响应缺少 {Code,Message,Data} 信封。', meta.status)\n }\n const envelope = body as { Code?: unknown; Message?: unknown; Data?: unknown }\n const rawCode = envelope.Code\n if (!((typeof rawCode === 'number' && Number.isSafeInteger(rawCode))\n || (typeof rawCode === 'string' && /^\\d+$/.test(rawCode) && Number.isSafeInteger(Number(rawCode))))) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎响应缺少有效的 Code 字段。', meta.status)\n }\n const code = Number(rawCode)\n if (code !== 0) {\n const message = typeof envelope.Message === 'string' && envelope.Message ? envelope.Message : '未知错误'\n if (code === 30003) {\n throw new ZhihuSearchError('UPSTREAM_UNAVAILABLE', `知乎开放平台被风控拒绝:${message}。请不要立即重试。`,\n meta.status, { upstreamCode: code, retryable: false })\n }\n const kind = ZHIHU_BUSINESS_ERRORS[code] ?? (meta.officialErrors ? 'UPSTREAM_UNAVAILABLE' : 'HTTP_ERROR')\n throw new ZhihuSearchError(kind, `知乎开放平台返回错误(code=${code}):${message}`, meta.status,\n { upstreamCode: code, ...(kind === 'RATE_LIMITED' ? { retryAfter: meta.retryAfter, retryable: true } : {}) })\n }\n return envelope.Data ?? {}\n}\n\nfunction truncateSummary(text: string, limit: number): string {\n if (text.length <= limit) return text\n return `${text.slice(0, limit)}…`\n}\n\n/** 搜索类接口(站内/全网)共用的条目结构。 */\nexport type ZhihuSearchItem = {\n title: string\n type: string\n url: string\n summary: string\n votes: number\n comments: number\n author: string\n authority: string\n editTime: string\n}\n\nexport function normalizeSearchItem(raw: Record<string, unknown>): ZhihuSearchItem {\n const summary = typeof raw.ContentText === 'string' ? raw.ContentText : ''\n return {\n title: typeof raw.Title === 'string' && raw.Title.length > 0 ? raw.Title : '(无标题)',\n type: typeof raw.ContentType === 'string' && raw.ContentType.length > 0 ? raw.ContentType : '内容',\n url: typeof raw.Url === 'string' ? raw.Url : '',\n summary: truncateSummary(summary.trim(), ZHIHU_SUMMARY_MAX_CHARS),\n votes: typeof raw.VoteUpCount === 'number' ? raw.VoteUpCount : 0,\n comments: typeof raw.CommentCount === 'number' ? raw.CommentCount : 0,\n author: typeof raw.AuthorName === 'string' && raw.AuthorName.length > 0 ? raw.AuthorName : '匿名',\n authority: typeof raw.AuthorityLevel === 'string' && raw.AuthorityLevel.length > 0 ? raw.AuthorityLevel : '?',\n editTime: typeof raw.EditTime === 'number' ? String(raw.EditTime) : '',\n }\n}\n","/**\n * 知乎开放平台站内搜索工具。\n *\n * 端点调研结论(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 知乎站内搜索:GET /api/v1/content/zhihu_search?Query=<q>&Count=<n>\n * - count 上限 10\n * - 响应信封:{ Code, Message, Data };Code 非 0 表示业务错误。\n * - Data.Items: 每条 { Title, ContentType, Url, ContentText, VoteUpCount,\n * CommentCount, AuthorName, AuthorityLevel, EditTime }。\n *\n * 鉴权、超时、信封解析与计量走 ./zhihu-client.ts 的共享实现;此处只保留\n * 站内搜索的参数收敛、结果规整与工具定义。\n */\nimport { ZHIHU_SEARCH_TOOL_NAME } from './contracts.ts'\nimport {\n normalizeSearchItem,\n parseZhihuEnvelope,\n reportExecuted,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n type ZhihuSearchItem,\n} from './zhihu-client.ts'\n\nexport { ZHIHU_SEARCH_TOOL_NAME } from './contracts.ts'\nexport {\n resolveZhihuToken,\n ZhihuSearchError,\n type ZhihuSearchExecuted,\n type ZhihuSearchFetcher,\n type ZhihuSearchItem,\n type ZhihuSearchResolveOptions,\n type ZhihuSearchToken,\n} from './zhihu-client.ts'\nexport const ZHIHU_SEARCH_VERSION = 1\nexport const ZHIHU_SEARCH_DEFAULT_COUNT = 5\nexport const ZHIHU_SEARCH_MAX_COUNT = 10\nexport const ZHIHU_SEARCH_TIMEOUT_MS = 15_000\nexport const ZHIHU_SUMMARY_MAX_CHARS = 200\n\nconst ZHIHU_SEARCH_PATH = '/api/v1/content/zhihu_search'\n\nexport type ZhihuSearchResult = {\n version: typeof ZHIHU_SEARCH_VERSION\n query: string\n count: number\n items: ZhihuSearchItem[]\n emptyReason?: string\n}\n\nexport type ZhihuSearchExecuteOptions = ZhihuClientOptions\n\nfunction clampCount(value: unknown): number {\n const n = typeof value === 'number' && Number.isFinite(value) ? Math.trunc(value) : ZHIHU_SEARCH_DEFAULT_COUNT\n if (n < 1) return 1\n if (n > ZHIHU_SEARCH_MAX_COUNT) return ZHIHU_SEARCH_MAX_COUNT\n return n\n}\n\nfunction filterItems(data: unknown): { items: Record<string, unknown>[]; emptyReason?: string } {\n const row = (data ?? {}) as { Items?: unknown; EmptyReason?: unknown }\n const items = Array.isArray(row.Items) ? row.Items.filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item)) : []\n const emptyReason = typeof row.EmptyReason === 'string' ? row.EmptyReason : undefined\n return { items, emptyReason }\n}\n\nexport async function executeZhihuSearch(\n query: string,\n count: number,\n options: ZhihuSearchExecuteOptions = {},\n): Promise<ZhihuSearchResult> {\n const trimmed = query.trim()\n if (!trimmed) throw new ZhihuSearchError('BAD_RESPONSE', '搜索词不能为空。')\n const resolvedCount = clampCount(count)\n const body = await zhihuFetchJson(ZHIHU_SEARCH_PATH, {\n params: { Query: trimmed, Count: String(resolvedCount) },\n }, '知乎搜索', options)\n const { items, emptyReason } = filterItems(parseZhihuEnvelope(body))\n return {\n version: ZHIHU_SEARCH_VERSION,\n query: trimmed,\n count: resolvedCount,\n items: items.map(normalizeSearchItem),\n emptyReason,\n }\n}\n\nexport function renderZhihuSearch(result: ZhihuSearchResult): string {\n if (result.items.length === 0) {\n return `知乎站内搜索「${result.query}」无结果${result.emptyReason ? `(${result.emptyReason})` : ''}。`\n }\n const lines: string[] = [`知乎站内搜索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n lines.push(` - 类型:${item.type} 作者:${item.author} 权威:${item.authority}`)\n if (item.editTime) lines.push(` - 时间:${item.editTime}`)\n lines.push(` - 赞同 ${item.votes} 评论 ${item.comments}`)\n if (item.summary) lines.push(` - 摘要:${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n","/**\n * 知乎开放平台的其余写作向能力:全网搜索、热榜、直答、公开知识库检索。\n * 共享 ./zhihu-client.ts 的鉴权、超时、信封解析与计量;每个工具只做参数收敛、\n * 结果规整与渲染。结果一律只作社区参考,不构成 canon,也不写入项目文件。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 全网搜索:GET /api/v1/content/global_search?Query&Count(<=20)&SearchDB(all|realtime|static)\n * - 热榜:GET /api/v1/content/hot_list?Limit(<=30)\n * - 直答:POST /v1/chat/completions(OpenAI 兼容,非信封;模型 zhida-fast-1p5 / zhida-thinking-1p5)\n * - 知识库检索:POST /api/v1/knowledge/search { Query, Limit(<=10), RecallScopes }\n */\nimport {\n ZHIHU_ASK_TOOL_NAME,\n ZHIHU_GLOBAL_SEARCH_TOOL_NAME,\n ZHIHU_HOT_LIST_TOOL_NAME,\n ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,\n} from './contracts.ts'\nimport {\n normalizeSearchItem,\n parseZhihuEnvelope,\n reportExecuted,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n type ZhihuSearchExecuted,\n type ZhihuSearchItem,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_GLOBAL_SEARCH_VERSION = 1\nexport const ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT = 10\nexport const ZHIHU_GLOBAL_SEARCH_MAX_COUNT = 20\nexport const ZHIHU_HOT_LIST_VERSION = 1\nexport const ZHIHU_HOT_LIST_DEFAULT_LIMIT = 10\nexport const ZHIHU_HOT_LIST_MAX_LIMIT = 30\nexport const ZHIHU_ASK_VERSION = 1\nexport const ZHIHU_ASK_TIMEOUT_MS = 120_000\nexport const ZHIHU_KNOWLEDGE_SEARCH_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT = 5\nexport const ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT = 10\n\nconst GLOBAL_SEARCH_PATH = '/api/v1/content/global_search'\nconst HOT_LIST_PATH = '/api/v1/content/hot_list'\nconst ASK_PATH = '/v1/chat/completions'\nconst KNOWLEDGE_SEARCH_PATH = '/api/v1/knowledge/search'\n\nexport const ZHIHU_ASK_MODELS = ['zhida-fast-1p5', 'zhida-thinking-1p5', 'zhida-agent'] as const\nexport type ZhihuAskModel = (typeof ZHIHU_ASK_MODELS)[number]\n/** 直答的价值在于比本机模型更强的综合考据,默认用思考档;fast 只配简单事实查询。 */\nexport const ZHIHU_ASK_DEFAULT_MODEL: ZhihuAskModel = 'zhida-thinking-1p5'\n\nexport type ZhihuToolOptions = ZhihuClientOptions & {\n /** Best-effort metering hook; invoked after every execution, failures included. */\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction clampInt(value: unknown, fallback: number, max: number): number {\n const n = typeof value === 'number' && Number.isFinite(value) ? Math.trunc(value) : fallback\n if (n < 1) return 1\n if (n > max) return max\n return n\n}\n\nfunction requireQuery(query: string, hint: string): string {\n const trimmed = query.trim()\n if (!trimmed) throw new ZhihuSearchError('BAD_RESPONSE', hint)\n return trimmed\n}\n\nfunction objectItems(data: unknown, key = 'Items'): Record<string, unknown>[] {\n const row = (data ?? {}) as Record<string, unknown>\n const items = row[key]\n return Array.isArray(items) ? items.filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item)) : []\n}\n\n// ---------------------------------------------------------------------------\n// 全网搜索\n// ---------------------------------------------------------------------------\n\nexport type ZhihuGlobalSearchDb = 'all' | 'realtime' | 'static'\n\nexport type ZhihuGlobalSearchResult = {\n version: typeof ZHIHU_GLOBAL_SEARCH_VERSION\n query: string\n count: number\n searchDb: ZhihuGlobalSearchDb\n items: ZhihuSearchItem[]\n emptyReason?: string\n}\n\nexport async function executeZhihuGlobalSearch(\n query: string,\n count: number,\n searchDb: ZhihuGlobalSearchDb,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuGlobalSearchResult> {\n const trimmed = requireQuery(query, '搜索词不能为空。')\n const resolvedCount = clampInt(count, ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT, ZHIHU_GLOBAL_SEARCH_MAX_COUNT)\n const body = await zhihuFetchJson(GLOBAL_SEARCH_PATH, {\n params: { Query: trimmed, Count: String(resolvedCount), SearchDB: searchDb },\n }, '知乎全网搜索', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown; EmptyReason?: unknown }\n return {\n version: ZHIHU_GLOBAL_SEARCH_VERSION,\n query: trimmed,\n count: resolvedCount,\n searchDb,\n items: objectItems(data).map(normalizeSearchItem),\n emptyReason: typeof data.EmptyReason === 'string' ? data.EmptyReason : undefined,\n }\n}\n\nexport function renderZhihuGlobalSearch(result: ZhihuGlobalSearchResult): string {\n if (result.items.length === 0) {\n return `全网搜索「${result.query}」无结果${result.emptyReason ? `(${result.emptyReason})` : ''}。`\n }\n const lines: string[] = [`全网搜索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n lines.push(` - 类型:${item.type} 作者:${item.author}`)\n if (item.summary) lines.push(` - 摘要:${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 热榜\n// ---------------------------------------------------------------------------\n\nexport type ZhihuHotListItem = {\n title: string\n url: string\n summary: string\n}\n\nexport type ZhihuHotListResult = {\n version: typeof ZHIHU_HOT_LIST_VERSION\n limit: number\n items: ZhihuHotListItem[]\n}\n\nconst ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS = 200\n\nfunction normalizeHotItem(raw: Record<string, unknown>): ZhihuHotListItem {\n const summary = typeof raw.Summary === 'string' ? raw.Summary.trim() : ''\n return {\n title: typeof raw.Title === 'string' && raw.Title.length > 0 ? raw.Title : '(无标题)',\n url: typeof raw.Url === 'string' ? raw.Url : '',\n summary: summary.length > ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS ? `${summary.slice(0, ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS)}…` : summary,\n }\n}\n\nexport async function executeZhihuHotList(limit: number, options: ZhihuClientOptions = {}): Promise<ZhihuHotListResult> {\n const resolvedLimit = clampInt(limit, ZHIHU_HOT_LIST_DEFAULT_LIMIT, ZHIHU_HOT_LIST_MAX_LIMIT)\n const body = await zhihuFetchJson(HOT_LIST_PATH, {\n params: { Limit: String(resolvedLimit) },\n }, '知乎热榜', options)\n const items = objectItems(parseZhihuEnvelope(body)).map(normalizeHotItem)\n return { version: ZHIHU_HOT_LIST_VERSION, limit: resolvedLimit, items }\n}\n\nexport function renderZhihuHotList(result: ZhihuHotListResult): string {\n if (result.items.length === 0) return '知乎热榜为空。'\n const lines: string[] = ['知乎热榜:', '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n if (item.summary) lines.push(` - ${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 直答(OpenAI 兼容,非信封)\n// ---------------------------------------------------------------------------\n\nexport type ZhihuAskResult = {\n version: typeof ZHIHU_ASK_VERSION\n query: string\n model: ZhihuAskModel\n content: string\n reasoning: string\n}\n\nexport async function executeZhihuAsk(\n query: string,\n model: ZhihuAskModel,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuAskResult> {\n const trimmed = requireQuery(query, '直答问题不能为空。')\n const body = await zhihuFetchJson(ASK_PATH, {\n method: 'POST',\n body: { model, messages: [{ role: 'user', content: trimmed }], stream: false },\n }, '知乎直答', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_ASK_TIMEOUT_MS })\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎直答响应不是 OpenAI 兼容格式。')\n }\n const payload = body as {\n error?: { message?: unknown }\n choices?: Array<{ message?: { content?: unknown; reasoning_content?: unknown } }>\n }\n if (payload.error) {\n const msg = typeof payload.error.message === 'string' ? payload.error.message : '未知错误'\n throw new ZhihuSearchError('HTTP_ERROR', `知乎直答返回错误:${msg}`)\n }\n const choice = Array.isArray(payload.choices) ? payload.choices[0] : undefined\n const message = choice?.message ?? {}\n const content = typeof message.content === 'string' ? message.content.trim() : ''\n const reasoning = typeof message.reasoning_content === 'string' ? message.reasoning_content.trim() : ''\n if (!content) throw new ZhihuSearchError('BAD_RESPONSE', '知乎直答返回为空。')\n return { version: ZHIHU_ASK_VERSION, query: trimmed, model, content, reasoning }\n}\n\nexport function renderZhihuAsk(result: ZhihuAskResult): string {\n const parts: string[] = []\n if (result.reasoning) parts.push(`【思考过程】\\n${result.reasoning}`)\n parts.push(result.content)\n return `知乎直答「${result.query}」:\\n\\n${parts.join('\\n\\n')}`\n}\n\n// ---------------------------------------------------------------------------\n// 公开知识库检索\n// ---------------------------------------------------------------------------\n\nexport type ZhihuKnowledgeItem = {\n docName: string\n originUrl: string\n snippets: string[]\n}\n\nexport type ZhihuRecallScope = 'personal' | 'subscription' | 'public'\nexport const ZHIHU_RECALL_SCOPES: readonly ZhihuRecallScope[] = ['personal', 'subscription', 'public']\n\nexport type ZhihuKnowledgeSearchResult = {\n version: typeof ZHIHU_KNOWLEDGE_SEARCH_VERSION\n query: string\n limit: number\n recallScopes: ZhihuRecallScope[]\n items: ZhihuKnowledgeItem[]\n}\n\nfunction normalizeKnowledgeItem(raw: Record<string, unknown>): ZhihuKnowledgeItem {\n const content = raw.Content\n const snippets = Array.isArray(content)\n ? content.map((snippet) => String(snippet).trim()).filter((snippet) => snippet.length > 0)\n : []\n return {\n docName: typeof raw.DocName === 'string' && raw.DocName.length > 0 ? raw.DocName : '(未命名文档)',\n originUrl: typeof raw.OriginUrl === 'string' ? raw.OriginUrl : '',\n snippets,\n }\n}\n\n/** 收敛召回范围:只保留合法档位、去重;为空或未提供时回退公开库。 */\nexport function normalizeRecallScopes(value: unknown): ZhihuRecallScope[] {\n if (!Array.isArray(value)) return ['public']\n const scopes = [...new Set(value.filter((scope): scope is ZhihuRecallScope => typeof scope === 'string' && (ZHIHU_RECALL_SCOPES as readonly string[]).includes(scope)))]\n return scopes.length > 0 ? scopes : ['public']\n}\n\nexport async function executeZhihuKnowledgeSearch(\n query: string,\n limit: number,\n recallScopes: ZhihuRecallScope[],\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeSearchResult> {\n const trimmed = requireQuery(query, '知识库检索词不能为空。')\n const resolvedLimit = clampInt(limit, ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT, ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT)\n const body = await zhihuFetchJson(KNOWLEDGE_SEARCH_PATH, {\n method: 'POST',\n body: { Query: trimmed, Limit: resolvedLimit, RecallScopes: recallScopes },\n }, '知乎知识库检索', { ...options, timeoutMs: options.timeoutMs ?? 30_000 })\n const items = objectItems(parseZhihuEnvelope(body)).map(normalizeKnowledgeItem)\n return { version: ZHIHU_KNOWLEDGE_SEARCH_VERSION, query: trimmed, limit: resolvedLimit, recallScopes, items }\n}\n\nexport function renderZhihuKnowledgeSearch(result: ZhihuKnowledgeSearchResult): string {\n if (result.items.length === 0) return `知乎知识库检索「${result.query}」无匹配结果。`\n const lines: string[] = [`知乎知识库检索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. ${item.docName}`)\n if (item.originUrl) lines.push(` - 来源:${item.originUrl}`)\n for (const snippet of item.snippets) lines.push(` - ${snippet}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 工具定义\n// ---------------------------------------------------------------------------\n\n","/**\n * Contract source: klarkxy/zhihu-search@62fd3ce5, upstream/http_client.py.\n * Six question/creator APIs use the current Access Secret only, never OAuth.\n * This module has no DSH/UI dependencies; RPC and tools share these validators.\n */\nimport { zhihuFetchJson, ZhihuSearchError, type ZhihuClientOptions } from './zhihu-client.ts'\nimport { ZHIHU_QUOTA_IDS, type ZhihuQuotaId } from './contracts.ts'\n\nexport const ZHIHU_OPEN_PLATFORM_APIS = {\n 'question.recommendations': { path: '/api/v1/user/question_recommendations', label: '适合回答的问题', quotaId: 'creator' },\n 'question.answers': { path: '/api/v1/content/question_answers', label: '问题回答摘要', quotaId: 'question_answers' },\n 'content.detail': { path: '/api/v1/user/content_detail', label: '本人创作全文', quotaId: 'creator' },\n 'content.comments': { path: '/api/v1/user/content_comments', label: '本人创作评论', quotaId: 'creator' },\n 'creator.account.stats': { path: '/api/v1/user/creator_account_stats', label: '账号创作数据', quotaId: 'creator' },\n 'creator.content.stats': { path: '/api/v1/user/creator_content_stats', label: '单篇创作数据', quotaId: 'creator' },\n quota: { path: '/api/v1/quota', label: '官方每日额度', quotaId: undefined },\n} as const\nexport type ZhihuOpenPlatformOperation = keyof typeof ZHIHU_OPEN_PLATFORM_APIS\n\nconst ENDPOINT_ALIASES: Record<string, ZhihuOpenPlatformOperation> = {\n question_recommendations: 'question.recommendations', question_answers: 'question.answers',\n content_detail: 'content.detail', user_content_detail: 'content.detail', 'user.content.detail': 'content.detail',\n content_comments: 'content.comments', user_content_comments: 'content.comments', 'user.content.comments': 'content.comments',\n creator_account_stats: 'creator.account.stats', creator_content_stats: 'creator.content.stats',\n}\nexport function resolveZhihuOpenPlatformOperation(endpoint: string): ZhihuOpenPlatformOperation | undefined {\n if (Object.hasOwn(ZHIHU_OPEN_PLATFORM_APIS, endpoint)) return endpoint as ZhihuOpenPlatformOperation\n return Object.hasOwn(ENDPOINT_ALIASES, endpoint) ? ENDPOINT_ALIASES[endpoint] : undefined\n}\n\nexport type ZhihuPaging = {\n canContinue: boolean\n isEnd?: boolean\n /** Decimal Int64 string. Never synthesize this from the number of items. */\n nextOffset?: string\n warning?: string\n}\nexport type ZhihuJsonValue = string | number | boolean | null | ZhihuJsonValue[] | { [key: string]: ZhihuJsonValue }\nexport type ZhihuOpenPlatformResult = {\n version: 1\n operation: ZhihuOpenPlatformOperation\n quotaId?: ZhihuQuotaId\n /** Original Data fields. Quota's top-level array is wrapped in { Items }. */\n data: Record<string, ZhihuJsonValue>\n paging?: ZhihuPaging\n}\nexport type ZhihuPageInput = { offset?: number | string; limit?: number }\nexport type ZhihuDateInput = { startDate?: string; endDate?: string }\nexport type ZhihuCreatorContentType = 'all' | 'answer' | 'article' | 'pin' | 'zvideo'\nexport type ZhihuCommentOrder = 'score' | 'reverse' | 'ascending'\n\nconst record = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value)\n// Keep the free-form tool result compatible with the SDK's JSON value contract.\nfunction jsonValue(value: unknown): value is ZhihuJsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true\n if (typeof value === 'number') return Number.isFinite(value)\n if (Array.isArray(value)) return value.every(jsonValue)\n return record(value) && Object.values(value).every(jsonValue)\n}\nfunction jsonRecord(value: unknown): value is Record<string, ZhihuJsonValue> {\n return record(value) && Object.values(value).every(jsonValue)\n}\nfunction invalid(message: string): never { throw new ZhihuSearchError('INVALID_ARGUMENTS', message) }\n\nfunction inputObject(input: unknown): Record<string, unknown> {\n if (!record(input)) return invalid('参数必须是对象。')\n // Reject misleading identity overrides, even over raw RPC. Credentials belong to the host.\n for (const key of ['token', 'accessSecret', 'access_secret', 'accessToken', 'access_token', 'oauthToken', 'oauth_token', 'useConfiguredOauthUser', 'use_configured_oauth_user']) {\n if (Object.hasOwn(input, key)) invalid('这些接口仅使用当前 Access Secret,不接受 token 参数或 OAuth 身份切换。')\n }\n return input\n}\nfunction limit(value: unknown, fallback: number, maximum: number, name = 'limit'): string {\n const count = value === undefined ? fallback : value\n if (typeof count !== 'number' || !Number.isInteger(count) || count < 1 || count > maximum) {\n return invalid(`${name} 必须是 1-${maximum} 的整数。`)\n }\n return String(count)\n}\n\n/** Accept all nonnegative Int64 values as strings, but never accept an unsafe JS number. */\nexport function normalizeZhihuOffset(value: unknown): string {\n let decimal: string\n if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) decimal = String(value)\n else if (typeof value === 'string' && /^\\d+$/.test(value)) decimal = value.replace(/^0+(?=\\d)/, '')\n else return invalid('offset 必须是非负 Int64 整数;超过 JavaScript 安全整数范围时请用十进制字符串,不能使用不透明游标。')\n if (decimal.length > 19 || BigInt(decimal) > 9223372036854775807n) return invalid('offset 超出 Int64 范围。')\n return decimal\n}\n\nfunction zhihuUrl(value: unknown, question: boolean): string {\n if (typeof value !== 'string' || !value.trim()) return invalid(question ? 'questionUrl 不能为空。' : 'contentUrl 不能为空。')\n const cleaned = value.trim()\n if (/[\\u0000-\\u0020\\u007f\\\\]/.test(cleaned)) return invalid('知乎链接不能包含空白、控制字符或反斜线。')\n let url: URL\n try { url = new URL(cleaned) } catch { return invalid('不是有效的知乎 URL。') }\n if (url.protocol !== 'https:' || url.username || url.password || url.port) return invalid('必须使用无账号密码、无非标准端口的 HTTPS 知乎链接。')\n const valid = question\n ? url.hostname === 'www.zhihu.com' && /^\\/question\\/\\d+\\/?$/.test(url.pathname)\n : (url.hostname === 'www.zhihu.com' && /^\\/(?:answer\\/\\d+|question\\/\\d+\\/answer\\/\\d+|pin\\/\\d+|zvideo\\/\\d+)\\/?$/.test(url.pathname))\n || (url.hostname === 'zhuanlan.zhihu.com' && /^\\/p\\/\\d+\\/?$/.test(url.pathname))\n if (!valid) return invalid(question ? 'questionUrl 仅支持 https://www.zhihu.com/question/{id}。' : 'contentUrl 仅支持知乎回答、专栏文章、想法或视频链接。')\n return cleaned\n}\n\nfunction dates(input: Record<string, unknown>, params: Record<string, string>): void {\n const { startDate, endDate } = input\n if (startDate === undefined && endDate === undefined) return\n if (startDate === undefined || endDate === undefined) invalid('startDate 与 endDate 必须同时提供或同时省略。')\n for (const [key, value] of [['StartDate', startDate], ['EndDate', endDate]] as const) {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) || value.slice(0, 4) === '0000') invalid(`${key} 必须是有效的 YYYY-MM-DD 公历日期。`)\n const time = new Date(`${value}T00:00:00Z`)\n if (!Number.isFinite(time.getTime()) || time.toISOString().slice(0, 10) !== value) invalid(`${key} 不是有效公历日期。`)\n params[key] = value\n }\n if (params.EndDate! < params.StartDate!) invalid('endDate 不得早于 startDate。')\n}\n\nfunction paramsFor(operation: ZhihuOpenPlatformOperation, input: Record<string, unknown>): Record<string, string> {\n const params: Record<string, string> = {}\n if (operation === 'question.recommendations') {\n // Explicit null/blank is not the same as omitting Query.\n if (input.query !== undefined) {\n if (typeof input.query !== 'string' || !input.query.trim()) invalid('主题关键词不能为空;省略 query 才会按画像推荐。')\n params.Query = input.query.trim()\n }\n params.Count = limit(input.count, 5, 20, 'count')\n } else if (operation === 'question.answers') {\n params.QuestionUrl = zhihuUrl(input.questionUrl, true)\n } else if (operation === 'content.detail' || operation === 'content.comments' || operation === 'creator.content.stats') {\n params.ContentUrl = zhihuUrl(input.contentUrl, false)\n } else if (operation === 'creator.account.stats') {\n const type = input.contentType === undefined ? 'all' : input.contentType\n if (typeof type !== 'string' || !['all', 'answer', 'article', 'pin', 'zvideo'].includes(type)) invalid('contentType 必须是 all、answer、article、pin 或 zvideo。')\n params.ContentType = type\n } else if (operation === 'quota' && input.apiIds !== undefined) {\n if (!Array.isArray(input.apiIds) || input.apiIds.some(id => typeof id !== 'string' || !(ZHIHU_QUOTA_IDS as readonly string[]).includes(id))) invalid('apiIds 包含未知官方额度项。')\n if (input.apiIds.length) params.APIIDs = [...new Set(input.apiIds)].join(',')\n }\n if (operation === 'question.answers' || operation === 'content.comments') {\n params.Offset = normalizeZhihuOffset(input.offset === undefined ? 0 : input.offset)\n params.Limit = limit(input.limit, 20, 50)\n }\n if (operation === 'content.comments') {\n const order = input.order === undefined ? 'score' : input.order\n if (typeof order !== 'string' || !['score', 'reverse', 'ascending'].includes(order)) invalid('order 必须是 score、reverse 或 ascending。')\n params.Order = order\n }\n if (operation === 'creator.account.stats' || operation === 'creator.content.stats') dates(input, params)\n return params\n}\n\nexport function normalizeZhihuPaging(data: Record<string, unknown>, offset: string): ZhihuPaging {\n const paging = data.Paging\n if (!record(paging) || typeof paging.IsEnd !== 'boolean') {\n return { canContinue: false, warning: '分页信息不完整:缺少有效的 Paging.IsEnd,请停止翻页。' }\n }\n if (paging.IsEnd) return { isEnd: true, canContinue: false }\n try {\n const nextOffset = normalizeZhihuOffset(paging.NextOffset)\n if (BigInt(nextOffset) <= BigInt(offset)) throw new Error('non-advancing offset')\n return { isEnd: false, canContinue: true, nextOffset }\n } catch {\n return { isEnd: false, canContinue: false, warning: '分页信息不完整:NextOffset 缺失、无效或未前进,请停止翻页;不要按条数计算偏移。' }\n }\n}\n\nexport async function executeZhihuOpenPlatform(\n operation: ZhihuOpenPlatformOperation,\n input: unknown = {},\n options: ZhihuClientOptions = {},\n): Promise<ZhihuOpenPlatformResult> {\n const args = inputObject(input)\n const params = paramsFor(operation, args)\n const api = ZHIHU_OPEN_PLATFORM_APIS[operation]\n const raw = await zhihuFetchJson(api.path, { params, envelope: true }, api.label, options)\n const data = operation === 'quota' && Array.isArray(raw) ? { Items: raw } : raw\n if (!jsonRecord(data)) throw new ZhihuSearchError('BAD_RESPONSE', `${api.label}的 Data 必须是 JSON 对象。`)\n return {\n version: 1, operation, data,\n ...(api.quotaId ? { quotaId: api.quotaId } : {}),\n ...(operation === 'question.answers' || operation === 'content.comments'\n ? { paging: normalizeZhihuPaging(data, params.Offset!) } : {}),\n }\n}\n\n// Typed client entry points. Authentication stays in ZhihuClientOptions, never input.\nexport const executeZhihuQuestionRecommendations = (args: { query?: string; count?: number } = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('question.recommendations', args, options)\nexport const executeZhihuQuestionAnswers = (args: { questionUrl: string } & ZhihuPageInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('question.answers', args, options)\nexport const executeZhihuUserContentDetail = (args: { contentUrl: string }, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('content.detail', args, options)\nexport const executeZhihuUserContentComments = (args: { contentUrl: string; order?: ZhihuCommentOrder } & ZhihuPageInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('content.comments', args, options)\nexport const executeZhihuCreatorAccountStats = (args: { contentType?: ZhihuCreatorContentType } & ZhihuDateInput = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('creator.account.stats', args, options)\nexport const executeZhihuCreatorContentStats = (args: { contentUrl: string } & ZhihuDateInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('creator.content.stats', args, options)\nexport const executeZhihuQuota = (args: { apiIds?: ZhihuQuotaId[] } = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('quota', args, options)\n\nexport function zhihuOpenPlatformResultCount(result: ZhihuOpenPlatformResult): number {\n if (result.operation === 'quota') return 0\n if (result.operation === 'content.detail') return typeof result.data.Body === 'string' && result.data.Body.trim() ? 1 : 0\n if (result.operation === 'creator.account.stats') return Object.keys(result.data).length ? 1 : 0\n return Array.isArray(result.data.Items) ? result.data.Items.filter(record).length : 0\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"open-platform.js","names":[],"sources":["../src/zhihu-client.ts","../src/search-api.ts","../src/operations.ts","../src/open-platform.ts"],"sourcesContent":["/**\n * 知乎开放平台共享请求层:Access Secret 解析、超时封装、信封解析与执行计量。\n *\n * 端点规范(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - Base URL: https://developer.zhihu.com\n * - 公共 Headers: Authorization: Bearer <access_secret>、X-Request-Timestamp、Accept\n * - 除直答外的 REST 接口返回 {Code, Message, Data} 信封,Code 非 0 表示业务错误。\n *\n * Token 解析(按契约,**不**把 token 放进 schema 参数):\n * - 提供 credential 解析器时只使用它,缺失或无效时抛出 TOKEN_MISSING。\n * 宿主通过 `ctx.credentials.resolve` 统一管理凭据来源和清除操作。\n * - 未提供解析器的独立客户端依次兼容 ZHIHU_ACCESS_TOKEN、\n * ZHIHU_ACCESS_SECRET 和 ~/.config/zhihu-search/credentials.json。\n */\nimport { readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { ZhihuQuotaId } from './contracts.ts'\n\nexport const ZHIHU_BASE_URL = 'https://developer.zhihu.com'\nexport const ZHIHU_DEFAULT_TIMEOUT_MS = 15_000\nexport const ZHIHU_SUMMARY_MAX_CHARS = 200\n\nconst ZHIHU_CREDENTIALS_PRIMARY = 'ZHIHU_ACCESS_TOKEN'\nconst ZHIHU_CREDENTIALS_FALLBACK = 'ZHIHU_ACCESS_SECRET'\nconst ZHIHU_CREDENTIALS_FILE = join(homedir(), '.config', 'zhihu-search', 'credentials.json')\n\ntype TokenSource = 'credential' | 'env-primary' | 'env-fallback' | 'file'\n\nexport type ZhihuSearchToken = { token: string; source: TokenSource }\n\nexport type ZhihuSearchFetcher = (input: string, init?: { method?: string; headers?: Record<string, string>; body?: string | FormData; signal?: AbortSignal }) => Promise<{\n ok: boolean\n status: number\n headers?: { get(name: string): string | null }\n text(): Promise<string>\n json(): Promise<unknown>\n}>\n\nconst globalFetch: ZhihuSearchFetcher | undefined = typeof globalThis !== 'undefined' && typeof (globalThis as { fetch?: unknown }).fetch === 'function'\n ? (input, init) => {\n const f = (globalThis as { fetch: typeof globalThis.fetch }).fetch\n return f(input as Parameters<typeof f>[0], init as Parameters<typeof f>[1] | undefined) as unknown as ReturnType<ZhihuSearchFetcher>\n }\n : undefined\n\nfunction looksLikeToken(value: string): boolean {\n const trimmed = value.trim()\n return trimmed.length >= 8 && trimmed.length <= 256\n}\n\nasync function readCredentialsFile(path: string): Promise<string | undefined> {\n try {\n const raw = await readFile(path, 'utf8')\n const parsed = JSON.parse(raw) as { access_secret?: unknown } | null\n if (parsed && typeof parsed === 'object' && typeof parsed.access_secret === 'string' && looksLikeToken(parsed.access_secret)) {\n return parsed.access_secret.trim()\n }\n } catch {\n // 文件不存在或 JSON 解析失败都不算硬错误,让上层回退到 isError 提示\n }\n return undefined\n}\n\nexport type ZhihuSearchResolveOptions = {\n /** Authoritative Access Secret resolver; absence/invalid values never fall back to env or CLI files. */\n resolveCredential?: () => Promise<string | undefined>\n}\n\nexport async function resolveZhihuToken(\n env: NodeJS.ProcessEnv = process.env,\n options: ZhihuSearchResolveOptions = {},\n): Promise<ZhihuSearchToken> {\n if (options.resolveCredential) {\n const value = await options.resolveCredential()\n const fromCredential = typeof value === 'string' ? value.trim() : undefined\n if (fromCredential && looksLikeToken(fromCredential)) {\n return { token: fromCredential, source: 'credential' }\n }\n throw new ZhihuSearchError('TOKEN_MISSING', '未配置有效的知乎 Access Secret。请在「插件 → 知乎 → 设置」中填写。')\n }\n const primary = env[ZHIHU_CREDENTIALS_PRIMARY]?.trim()\n if (primary && looksLikeToken(primary)) return { token: primary, source: 'env-primary' }\n const fallback = env[ZHIHU_CREDENTIALS_FALLBACK]?.trim()\n if (fallback && looksLikeToken(fallback)) return { token: fallback, source: 'env-fallback' }\n const fromFile = await readCredentialsFile(ZHIHU_CREDENTIALS_FILE)\n if (fromFile) return { token: fromFile, source: 'file' }\n throw new ZhihuSearchError('TOKEN_MISSING', [\n '未找到知乎 Access Secret。请在「设置 → 知乎」中填写;',\n `也可设置环境变量 ${ZHIHU_CREDENTIALS_PRIMARY} 或写入 ~/.config/zhihu-search/credentials.json。`,\n ].join(''))\n}\n\nexport type ZhihuErrorDetails = {\n upstreamCode?: number\n retryAfter?: number\n retryable?: boolean\n}\n\nexport class ZhihuSearchError extends Error {\n readonly code: 'TOKEN_MISSING' | 'HTTP_ERROR' | 'TIMEOUT' | 'BAD_RESPONSE'\n | 'INVALID_ARGUMENTS' | 'TOKEN_INVALID' | 'RATE_LIMITED' | 'UPSTREAM_UNAVAILABLE' | 'CANCELLED'\n readonly status?: number\n readonly upstreamCode?: number\n readonly retryAfter?: number\n readonly retryable?: boolean\n constructor(code: ZhihuSearchError['code'], message: string, status?: number, details: ZhihuErrorDetails = {}) {\n super(message)\n this.name = 'ZhihuSearchError'\n this.code = code\n if (status !== undefined) this.status = status\n if (details.upstreamCode !== undefined) this.upstreamCode = details.upstreamCode\n if (details.retryAfter !== undefined) this.retryAfter = details.retryAfter\n if (details.retryable !== undefined) this.retryable = details.retryable\n }\n}\n\n/** Metering payload emitted after each zhihu tool execution. */\nexport type ZhihuSearchExecuted = { ok: boolean; results: number; quotaId?: ZhihuQuotaId }\n\n/** Metering must never break the tool itself. */\nexport function reportExecuted(hook: ((event: ZhihuSearchExecuted) => void) | undefined, event: ZhihuSearchExecuted): void {\n if (!hook) return\n try {\n hook(event)\n } catch {\n // Best-effort metering; swallow hook failures.\n }\n}\n\nexport type ZhihuClientOptions = ZhihuSearchResolveOptions & {\n fetcher?: ZhihuSearchFetcher\n /** Allows tests to bypass process env; defaults to process.env. */\n env?: NodeJS.ProcessEnv\n signal?: AbortSignal\n /** Override the request timeout in ms. Defaults to {@link ZHIHU_DEFAULT_TIMEOUT_MS}. */\n timeoutMs?: number\n}\n\nfunction isAbortError(error: unknown): boolean {\n if (error instanceof Error && error.name === 'AbortError') return true\n return typeof error === 'object' && error !== null && (error as { name?: unknown }).name === 'AbortError'\n}\n\n/** Parse Retry-After seconds or an HTTP date; never invent a quota reset time. */\nexport function parseZhihuRetryAfter(value: string | null | undefined, now = Date.now()): number | undefined {\n if (!value?.trim()) return undefined\n const text = value.trim()\n if (/^\\d+(?:\\.\\d+)?$/.test(text)) {\n const seconds = Number(text)\n return Number.isFinite(seconds) ? Math.ceil(seconds) : undefined\n }\n // Do not let Date.parse interpret negative numbers as calendar dates.\n if (!/[a-z]/i.test(text)) return undefined\n const date = Date.parse(text)\n return Number.isFinite(date) ? Math.max(0, Math.ceil((date - now) / 1000)) : undefined\n}\n\n/**\n * Shared authenticated request. envelope=true opts into official error semantics\n * and returns Data. Legacy callers still receive the full JSON / chat response.\n * The timeout and cancellation cover BOTH headers and response-body consumption.\n * No requests are retried, including 429, exhausted quota, or risk-control denial.\n */\nexport async function zhihuFetchJson(\n path: string,\n init: { method?: 'GET' | 'POST'; params?: Record<string, string>; body?: unknown; formData?: FormData; envelope?: boolean },\n label: string,\n options: ZhihuClientOptions = {},\n): Promise<unknown> {\n const linked = options.signal\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n const url = new URL(path, ZHIHU_BASE_URL)\n if (url.origin !== ZHIHU_BASE_URL || url.username || url.password) {\n throw new ZhihuSearchError('INVALID_ARGUMENTS', '只允许请求知乎开放平台。')\n }\n for (const [key, value] of Object.entries(init.params ?? {})) url.searchParams.set(key, value)\n const token = await resolveZhihuToken(options.env, { resolveCredential: options.resolveCredential })\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n const fetcher = options.fetcher ?? globalFetch\n if (!fetcher) throw new ZhihuSearchError('BAD_RESPONSE', '当前环境没有可用的 fetch。')\n const method = init.method ?? (init.formData || init.body !== undefined ? 'POST' : 'GET')\n const timeout = options.timeoutMs !== undefined && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0\n ? options.timeoutMs : ZHIHU_DEFAULT_TIMEOUT_MS\n const controller = new AbortController()\n const onAbort = () => controller.abort(linked?.reason)\n if (linked?.aborted) onAbort()\n else linked?.addEventListener('abort', onAbort, { once: true })\n const timer = setTimeout(() => controller.abort(new Error('zhihu request timeout')), timeout)\n let stopWaiting = () => {}\n const aborted = new Promise<never>((_resolve, reject) => {\n const rejectAbort = () => reject(controller.signal.reason)\n if (controller.signal.aborted) rejectAbort()\n else {\n controller.signal.addEventListener('abort', rejectAbort, { once: true })\n stopWaiting = () => controller.signal.removeEventListener('abort', rejectAbort)\n }\n })\n try {\n const request = async () => {\n controller.signal.throwIfAborted()\n const response = await fetcher(url.toString(), {\n method,\n headers: {\n Authorization: `Bearer ${token.token}`,\n 'X-Request-Timestamp': String(Math.floor(Date.now() / 1000)),\n Accept: 'application/json',\n // Let fetch supply the multipart boundary.\n ...(method === 'POST' && !init.formData ? { 'Content-Type': 'application/json' } : {}),\n },\n signal: controller.signal,\n ...(init.formData ? { body: init.formData } : init.body !== undefined ? { body: JSON.stringify(init.body) } : {}),\n })\n const retryAfter = parseZhihuRetryAfter(response.headers?.get('Retry-After'))\n const httpError = () => {\n const code = response.status === 429 ? 'RATE_LIMITED'\n : init.envelope && (response.status === 401 || response.status === 403) ? 'TOKEN_INVALID'\n : 'HTTP_ERROR'\n return new ZhihuSearchError(code, `${label}返回 HTTP ${response.status}。`, response.status,\n code === 'RATE_LIMITED' ? { retryAfter, retryable: true } : {})\n }\n let body: unknown\n try { body = await response.json() }\n catch (error) {\n if (controller.signal.aborted) throw error\n if (!response.ok) throw httpError()\n throw new ZhihuSearchError('BAD_RESPONSE', `${label}响应不是合法 JSON。`)\n }\n controller.signal.throwIfAborted()\n // A business error remains meaningful even when the HTTP status is 400.\n const isEnvelope = body !== null && typeof body === 'object' && !Array.isArray(body) && 'Code' in body\n if (!response.ok && !isEnvelope) throw httpError()\n if (init.envelope || (isEnvelope && (body as { Code: unknown }).Code !== 0 && (body as { Code: unknown }).Code !== '0')) {\n const data = parseZhihuEnvelope(body, { status: response.status, retryAfter, officialErrors: init.envelope })\n if (!response.ok) throw httpError()\n if (init.envelope) return data\n }\n if (!response.ok) throw httpError()\n return body\n }\n return await Promise.race([request(), aborted])\n } catch (error) {\n if (linked?.aborted) throw new ZhihuSearchError('CANCELLED', '请求已取消')\n if (controller.signal.aborted || isAbortError(error)) {\n throw new ZhihuSearchError('TIMEOUT', `${label}超时(${Math.round(timeout / 1000)} 秒),请稍后再试。`)\n }\n if (error instanceof ZhihuSearchError) {\n error.message = error.message.replaceAll(token.token, '[REDACTED]')\n throw error\n }\n const message = (error instanceof Error ? error.message : String(error)).replaceAll(token.token, '[REDACTED]')\n throw new ZhihuSearchError('BAD_RESPONSE', `${label}失败:${message}`)\n } finally {\n clearTimeout(timer)\n stopWaiting()\n linked?.removeEventListener('abort', onAbort)\n }\n}\n\nconst ZHIHU_BUSINESS_ERRORS: Record<number, ZhihuSearchError['code']> = {\n 10001: 'INVALID_ARGUMENTS', 20001: 'TOKEN_INVALID',\n 30001: 'RATE_LIMITED', 30002: 'RATE_LIMITED',\n 40001: 'INVALID_ARGUMENTS', 40002: 'INVALID_ARGUMENTS', 40003: 'RATE_LIMITED',\n 40004: 'INVALID_ARGUMENTS', 40005: 'INVALID_ARGUMENTS', 40006: 'INVALID_ARGUMENTS',\n 50002: 'UPSTREAM_UNAVAILABLE', 90001: 'UPSTREAM_UNAVAILABLE',\n}\n\n/** Parse the official envelope without coercing null/false/empty Code into success. */\nexport function parseZhihuEnvelope(body: unknown, meta: { status?: number; retryAfter?: number; officialErrors?: boolean } = {}): unknown {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎响应缺少 {Code,Message,Data} 信封。', meta.status)\n }\n const envelope = body as { Code?: unknown; Message?: unknown; Data?: unknown }\n const rawCode = envelope.Code\n if (!((typeof rawCode === 'number' && Number.isSafeInteger(rawCode))\n || (typeof rawCode === 'string' && /^\\d+$/.test(rawCode) && Number.isSafeInteger(Number(rawCode))))) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎响应缺少有效的 Code 字段。', meta.status)\n }\n const code = Number(rawCode)\n if (code !== 0) {\n const message = typeof envelope.Message === 'string' && envelope.Message ? envelope.Message : '未知错误'\n if (code === 30003) {\n throw new ZhihuSearchError('UPSTREAM_UNAVAILABLE', `知乎开放平台被风控拒绝:${message}。请不要立即重试。`,\n meta.status, { upstreamCode: code, retryable: false })\n }\n const kind = ZHIHU_BUSINESS_ERRORS[code] ?? (meta.officialErrors ? 'UPSTREAM_UNAVAILABLE' : 'HTTP_ERROR')\n throw new ZhihuSearchError(kind, `知乎开放平台返回错误(code=${code}):${message}`, meta.status,\n { upstreamCode: code, ...(kind === 'RATE_LIMITED' ? { retryAfter: meta.retryAfter, retryable: true } : {}) })\n }\n return envelope.Data ?? {}\n}\n\nfunction truncateSummary(text: string, limit: number): string {\n if (text.length <= limit) return text\n return `${text.slice(0, limit)}…`\n}\n\n/** 搜索类接口(站内/全网)共用的条目结构。 */\nexport type ZhihuSearchItem = {\n title: string\n type: string\n url: string\n summary: string\n votes: number\n comments: number\n author: string\n authority: string\n editTime: string\n}\n\nexport function normalizeSearchItem(raw: Record<string, unknown>): ZhihuSearchItem {\n const summary = typeof raw.ContentText === 'string' ? raw.ContentText : ''\n return {\n title: typeof raw.Title === 'string' && raw.Title.length > 0 ? raw.Title : '(无标题)',\n type: typeof raw.ContentType === 'string' && raw.ContentType.length > 0 ? raw.ContentType : '内容',\n url: typeof raw.Url === 'string' ? raw.Url : '',\n summary: truncateSummary(summary.trim(), ZHIHU_SUMMARY_MAX_CHARS),\n votes: typeof raw.VoteUpCount === 'number' ? raw.VoteUpCount : 0,\n comments: typeof raw.CommentCount === 'number' ? raw.CommentCount : 0,\n author: typeof raw.AuthorName === 'string' && raw.AuthorName.length > 0 ? raw.AuthorName : '匿名',\n authority: typeof raw.AuthorityLevel === 'string' && raw.AuthorityLevel.length > 0 ? raw.AuthorityLevel : '?',\n editTime: typeof raw.EditTime === 'number' ? String(raw.EditTime) : '',\n }\n}\n","/**\n * 知乎开放平台站内搜索工具。\n *\n * 端点调研结论(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 知乎站内搜索:GET /api/v1/content/zhihu_search?Query=<q>&Count=<n>\n * - count 上限 10\n * - 响应信封:{ Code, Message, Data };Code 非 0 表示业务错误。\n * - Data.Items: 每条 { Title, ContentType, Url, ContentText, VoteUpCount,\n * CommentCount, AuthorName, AuthorityLevel, EditTime }。\n *\n * 鉴权、超时、信封解析与计量走 ./zhihu-client.ts 的共享实现;此处只保留\n * 站内搜索的参数收敛、结果规整与工具定义。\n */\nimport { ZHIHU_SEARCH_TOOL_NAME } from './contracts.ts'\nimport {\n normalizeSearchItem,\n parseZhihuEnvelope,\n reportExecuted,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n type ZhihuSearchItem,\n} from './zhihu-client.ts'\n\nexport { ZHIHU_SEARCH_TOOL_NAME } from './contracts.ts'\nexport {\n resolveZhihuToken,\n ZhihuSearchError,\n type ZhihuSearchExecuted,\n type ZhihuSearchFetcher,\n type ZhihuSearchItem,\n type ZhihuSearchResolveOptions,\n type ZhihuSearchToken,\n} from './zhihu-client.ts'\nexport const ZHIHU_SEARCH_VERSION = 1\nexport const ZHIHU_SEARCH_DEFAULT_COUNT = 5\nexport const ZHIHU_SEARCH_MAX_COUNT = 10\nexport const ZHIHU_SEARCH_TIMEOUT_MS = 15_000\nexport const ZHIHU_SUMMARY_MAX_CHARS = 200\n\nconst ZHIHU_SEARCH_PATH = '/api/v1/content/zhihu_search'\n\nexport type ZhihuSearchResult = {\n version: typeof ZHIHU_SEARCH_VERSION\n query: string\n count: number\n items: ZhihuSearchItem[]\n emptyReason?: string\n}\n\nexport type ZhihuSearchExecuteOptions = ZhihuClientOptions\n\nfunction clampCount(value: unknown): number {\n const n = typeof value === 'number' && Number.isFinite(value) ? Math.trunc(value) : ZHIHU_SEARCH_DEFAULT_COUNT\n if (n < 1) return 1\n if (n > ZHIHU_SEARCH_MAX_COUNT) return ZHIHU_SEARCH_MAX_COUNT\n return n\n}\n\nfunction filterItems(data: unknown): { items: Record<string, unknown>[]; emptyReason?: string } {\n const row = (data ?? {}) as { Items?: unknown; EmptyReason?: unknown }\n const items = Array.isArray(row.Items) ? row.Items.filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item)) : []\n const emptyReason = typeof row.EmptyReason === 'string' ? row.EmptyReason : undefined\n return { items, emptyReason }\n}\n\nexport async function executeZhihuSearch(\n query: string,\n count: number,\n options: ZhihuSearchExecuteOptions = {},\n): Promise<ZhihuSearchResult> {\n const trimmed = query.trim()\n if (!trimmed) throw new ZhihuSearchError('BAD_RESPONSE', '搜索词不能为空。')\n const resolvedCount = clampCount(count)\n const body = await zhihuFetchJson(ZHIHU_SEARCH_PATH, {\n params: { Query: trimmed, Count: String(resolvedCount) },\n }, '知乎搜索', options)\n const { items, emptyReason } = filterItems(parseZhihuEnvelope(body))\n return {\n version: ZHIHU_SEARCH_VERSION,\n query: trimmed,\n count: resolvedCount,\n items: items.map(normalizeSearchItem),\n emptyReason,\n }\n}\n\nexport function renderZhihuSearch(result: ZhihuSearchResult): string {\n if (result.items.length === 0) {\n return `知乎站内搜索「${result.query}」无结果${result.emptyReason ? `(${result.emptyReason})` : ''}。`\n }\n const lines: string[] = [`知乎站内搜索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n lines.push(` - 类型:${item.type} 作者:${item.author} 权威:${item.authority}`)\n if (item.editTime) lines.push(` - 时间:${item.editTime}`)\n lines.push(` - 赞同 ${item.votes} 评论 ${item.comments}`)\n if (item.summary) lines.push(` - 摘要:${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n","/**\n * 知乎开放平台的其余写作向能力:全网搜索、热榜、直答、公开知识库检索。\n * 共享 ./zhihu-client.ts 的鉴权、超时、信封解析与计量;每个工具只做参数收敛、\n * 结果规整与渲染。结果一律只作社区参考,不构成 canon,也不写入项目文件。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 全网搜索:GET /api/v1/content/global_search?Query&Count(<=20)&SearchDB(all|realtime|static)\n * - 热榜:GET /api/v1/content/hot_list?Limit(<=30)\n * - 直答:POST /v1/chat/completions(OpenAI 兼容,非信封;模型 zhida-fast-1p5 / zhida-thinking-1p5)\n * - 知识库检索:POST /api/v1/knowledge/search { Query, Limit(<=10), RecallScopes }\n */\nimport {\n ZHIHU_ASK_TOOL_NAME,\n ZHIHU_GLOBAL_SEARCH_TOOL_NAME,\n ZHIHU_HOT_LIST_TOOL_NAME,\n ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,\n} from './contracts.ts'\nimport {\n normalizeSearchItem,\n parseZhihuEnvelope,\n reportExecuted,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n type ZhihuSearchExecuted,\n type ZhihuSearchItem,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_GLOBAL_SEARCH_VERSION = 1\nexport const ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT = 10\nexport const ZHIHU_GLOBAL_SEARCH_MAX_COUNT = 20\nexport const ZHIHU_HOT_LIST_VERSION = 1\nexport const ZHIHU_HOT_LIST_DEFAULT_LIMIT = 10\nexport const ZHIHU_HOT_LIST_MAX_LIMIT = 30\nexport const ZHIHU_ASK_VERSION = 1\nexport const ZHIHU_ASK_TIMEOUT_MS = 120_000\nexport const ZHIHU_KNOWLEDGE_SEARCH_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT = 5\nexport const ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT = 10\n\nconst GLOBAL_SEARCH_PATH = '/api/v1/content/global_search'\nconst HOT_LIST_PATH = '/api/v1/content/hot_list'\nconst ASK_PATH = '/v1/chat/completions'\nconst KNOWLEDGE_SEARCH_PATH = '/api/v1/knowledge/search'\n\nexport const ZHIHU_ASK_MODELS = ['zhida-fast-1p5', 'zhida-thinking-1p5', 'zhida-agent'] as const\nexport type ZhihuAskModel = (typeof ZHIHU_ASK_MODELS)[number]\n/** 直答的价值在于比本机模型更强的综合考据,默认用思考档;fast 只配简单事实查询。 */\nexport const ZHIHU_ASK_DEFAULT_MODEL: ZhihuAskModel = 'zhida-thinking-1p5'\n\nexport type ZhihuToolOptions = ZhihuClientOptions & {\n /** Best-effort metering hook; invoked after every execution, failures included. */\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction clampInt(value: unknown, fallback: number, max: number): number {\n const n = typeof value === 'number' && Number.isFinite(value) ? Math.trunc(value) : fallback\n if (n < 1) return 1\n if (n > max) return max\n return n\n}\n\nfunction requireQuery(query: string, hint: string): string {\n const trimmed = query.trim()\n if (!trimmed) throw new ZhihuSearchError('BAD_RESPONSE', hint)\n return trimmed\n}\n\nfunction objectItems(data: unknown, key = 'Items'): Record<string, unknown>[] {\n const row = (data ?? {}) as Record<string, unknown>\n const items = row[key]\n return Array.isArray(items) ? items.filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item)) : []\n}\n\n// ---------------------------------------------------------------------------\n// 全网搜索\n// ---------------------------------------------------------------------------\n\nexport type ZhihuGlobalSearchDb = 'all' | 'realtime' | 'static'\n\nexport type ZhihuGlobalSearchResult = {\n version: typeof ZHIHU_GLOBAL_SEARCH_VERSION\n query: string\n count: number\n searchDb: ZhihuGlobalSearchDb\n items: ZhihuSearchItem[]\n emptyReason?: string\n}\n\nexport async function executeZhihuGlobalSearch(\n query: string,\n count: number,\n searchDb: ZhihuGlobalSearchDb,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuGlobalSearchResult> {\n const trimmed = requireQuery(query, '搜索词不能为空。')\n const resolvedCount = clampInt(count, ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT, ZHIHU_GLOBAL_SEARCH_MAX_COUNT)\n const body = await zhihuFetchJson(GLOBAL_SEARCH_PATH, {\n params: { Query: trimmed, Count: String(resolvedCount), SearchDB: searchDb },\n }, '知乎全网搜索', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown; EmptyReason?: unknown }\n return {\n version: ZHIHU_GLOBAL_SEARCH_VERSION,\n query: trimmed,\n count: resolvedCount,\n searchDb,\n items: objectItems(data).map(normalizeSearchItem),\n emptyReason: typeof data.EmptyReason === 'string' ? data.EmptyReason : undefined,\n }\n}\n\nexport function renderZhihuGlobalSearch(result: ZhihuGlobalSearchResult): string {\n if (result.items.length === 0) {\n return `全网搜索「${result.query}」无结果${result.emptyReason ? `(${result.emptyReason})` : ''}。`\n }\n const lines: string[] = [`全网搜索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n lines.push(` - 类型:${item.type} 作者:${item.author}`)\n if (item.summary) lines.push(` - 摘要:${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 热榜\n// ---------------------------------------------------------------------------\n\nexport type ZhihuHotListItem = {\n title: string\n url: string\n summary: string\n}\n\nexport type ZhihuHotListResult = {\n version: typeof ZHIHU_HOT_LIST_VERSION\n limit: number\n items: ZhihuHotListItem[]\n}\n\nconst ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS = 200\n\nfunction normalizeHotItem(raw: Record<string, unknown>): ZhihuHotListItem {\n const summary = typeof raw.Summary === 'string' ? raw.Summary.trim() : ''\n return {\n title: typeof raw.Title === 'string' && raw.Title.length > 0 ? raw.Title : '(无标题)',\n url: typeof raw.Url === 'string' ? raw.Url : '',\n summary: summary.length > ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS ? `${summary.slice(0, ZHIHU_HOT_LIST_SUMMARY_MAX_CHARS)}…` : summary,\n }\n}\n\nexport async function executeZhihuHotList(limit: number, options: ZhihuClientOptions = {}): Promise<ZhihuHotListResult> {\n const resolvedLimit = clampInt(limit, ZHIHU_HOT_LIST_DEFAULT_LIMIT, ZHIHU_HOT_LIST_MAX_LIMIT)\n const body = await zhihuFetchJson(HOT_LIST_PATH, {\n params: { Limit: String(resolvedLimit) },\n }, '知乎热榜', options)\n const items = objectItems(parseZhihuEnvelope(body)).map(normalizeHotItem)\n return { version: ZHIHU_HOT_LIST_VERSION, limit: resolvedLimit, items }\n}\n\nexport function renderZhihuHotList(result: ZhihuHotListResult): string {\n if (result.items.length === 0) return '知乎热榜为空。'\n const lines: string[] = ['知乎热榜:', '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. [${item.title}](${item.url || '(无链接)'})`)\n if (item.summary) lines.push(` - ${item.summary}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 直答(OpenAI 兼容,非信封)\n// ---------------------------------------------------------------------------\n\nexport type ZhihuAskResult = {\n version: typeof ZHIHU_ASK_VERSION\n query: string\n model: ZhihuAskModel\n content: string\n reasoning: string\n}\n\nexport async function executeZhihuAsk(\n query: string,\n model: ZhihuAskModel,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuAskResult> {\n const trimmed = requireQuery(query, '直答问题不能为空。')\n const body = await zhihuFetchJson(ASK_PATH, {\n method: 'POST',\n body: { model, messages: [{ role: 'user', content: trimmed }], stream: false },\n }, '知乎直答', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_ASK_TIMEOUT_MS })\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知乎直答响应不是 OpenAI 兼容格式。')\n }\n const payload = body as {\n error?: { message?: unknown }\n choices?: Array<{ message?: { content?: unknown; reasoning_content?: unknown } }>\n }\n if (payload.error) {\n const msg = typeof payload.error.message === 'string' ? payload.error.message : '未知错误'\n throw new ZhihuSearchError('HTTP_ERROR', `知乎直答返回错误:${msg}`)\n }\n const choice = Array.isArray(payload.choices) ? payload.choices[0] : undefined\n const message = choice?.message ?? {}\n const content = typeof message.content === 'string' ? message.content.trim() : ''\n const reasoning = typeof message.reasoning_content === 'string' ? message.reasoning_content.trim() : ''\n if (!content) throw new ZhihuSearchError('BAD_RESPONSE', '知乎直答返回为空。')\n return { version: ZHIHU_ASK_VERSION, query: trimmed, model, content, reasoning }\n}\n\nexport function renderZhihuAsk(result: ZhihuAskResult): string {\n const parts: string[] = []\n if (result.reasoning) parts.push(`【思考过程】\\n${result.reasoning}`)\n parts.push(result.content)\n return `知乎直答「${result.query}」:\\n\\n${parts.join('\\n\\n')}`\n}\n\n// ---------------------------------------------------------------------------\n// 公开知识库检索\n// ---------------------------------------------------------------------------\n\nexport type ZhihuKnowledgeItem = {\n docName: string\n originUrl: string\n snippets: string[]\n}\n\nexport type ZhihuRecallScope = 'personal' | 'subscription' | 'public'\nexport const ZHIHU_RECALL_SCOPES: readonly ZhihuRecallScope[] = ['personal', 'subscription', 'public']\n\nexport type ZhihuKnowledgeSearchResult = {\n version: typeof ZHIHU_KNOWLEDGE_SEARCH_VERSION\n query: string\n limit: number\n recallScopes: ZhihuRecallScope[]\n items: ZhihuKnowledgeItem[]\n}\n\nfunction normalizeKnowledgeItem(raw: Record<string, unknown>): ZhihuKnowledgeItem {\n const content = raw.Content\n const snippets = Array.isArray(content)\n ? content.map((snippet) => String(snippet).trim()).filter((snippet) => snippet.length > 0)\n : []\n return {\n docName: typeof raw.DocName === 'string' && raw.DocName.length > 0 ? raw.DocName : '(未命名文档)',\n originUrl: typeof raw.OriginUrl === 'string' ? raw.OriginUrl : '',\n snippets,\n }\n}\n\n/** 收敛召回范围:只保留合法档位、去重;为空或未提供时回退公开库。 */\nexport function normalizeRecallScopes(value: unknown): ZhihuRecallScope[] {\n if (!Array.isArray(value)) return ['public']\n const scopes = [...new Set(value.filter((scope): scope is ZhihuRecallScope => typeof scope === 'string' && (ZHIHU_RECALL_SCOPES as readonly string[]).includes(scope)))]\n return scopes.length > 0 ? scopes : ['public']\n}\n\nexport async function executeZhihuKnowledgeSearch(\n query: string,\n limit: number,\n recallScopes: ZhihuRecallScope[],\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeSearchResult> {\n const trimmed = requireQuery(query, '知识库检索词不能为空。')\n const resolvedLimit = clampInt(limit, ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT, ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT)\n const body = await zhihuFetchJson(KNOWLEDGE_SEARCH_PATH, {\n method: 'POST',\n body: { Query: trimmed, Limit: resolvedLimit, RecallScopes: recallScopes },\n }, '知乎知识库检索', { ...options, timeoutMs: options.timeoutMs ?? 30_000 })\n const items = objectItems(parseZhihuEnvelope(body)).map(normalizeKnowledgeItem)\n return { version: ZHIHU_KNOWLEDGE_SEARCH_VERSION, query: trimmed, limit: resolvedLimit, recallScopes, items }\n}\n\nexport function renderZhihuKnowledgeSearch(result: ZhihuKnowledgeSearchResult): string {\n if (result.items.length === 0) return `知乎知识库检索「${result.query}」无匹配结果。`\n const lines: string[] = [`知乎知识库检索「${result.query}」共 ${result.items.length} 条:`, '']\n result.items.forEach((item, index) => {\n lines.push(`${index + 1}. ${item.docName}`)\n if (item.originUrl) lines.push(` - 来源:${item.originUrl}`)\n for (const snippet of item.snippets) lines.push(` - ${snippet}`)\n lines.push('')\n })\n return lines.join('\\n').trimEnd()\n}\n\n// ---------------------------------------------------------------------------\n// 工具定义\n// ---------------------------------------------------------------------------\n\n","/**\n * Contract source: klarkxy/zhihu-search@62fd3ce5, upstream/http_client.py.\n * Six question/creator APIs use the current Access Secret only, never OAuth.\n * This module has no DSH/UI dependencies; RPC and tools share these validators.\n */\nimport { zhihuFetchJson, ZhihuSearchError, type ZhihuClientOptions } from './zhihu-client.ts'\nimport { ZHIHU_QUOTA_IDS, type ZhihuQuotaId } from './contracts.ts'\n\nexport const ZHIHU_OPEN_PLATFORM_APIS = {\n 'question.recommendations': { path: '/api/v1/user/question_recommendations', label: '适合回答的问题', quotaId: 'creator' },\n 'question.answers': { path: '/api/v1/content/question_answers', label: '问题回答摘要', quotaId: 'question_answers' },\n 'content.detail': { path: '/api/v1/user/content_detail', label: '本人创作全文', quotaId: 'creator' },\n 'content.comments': { path: '/api/v1/user/content_comments', label: '本人创作评论', quotaId: 'creator' },\n 'creator.account.stats': { path: '/api/v1/user/creator_account_stats', label: '账号创作数据', quotaId: 'creator' },\n 'creator.content.stats': { path: '/api/v1/user/creator_content_stats', label: '单篇创作数据', quotaId: 'creator' },\n quota: { path: '/api/v1/quota', label: '官方每日额度', quotaId: undefined },\n} as const\nexport type ZhihuOpenPlatformOperation = keyof typeof ZHIHU_OPEN_PLATFORM_APIS\n\nconst ENDPOINT_ALIASES: Record<string, ZhihuOpenPlatformOperation> = {\n question_recommendations: 'question.recommendations', question_answers: 'question.answers',\n content_detail: 'content.detail', user_content_detail: 'content.detail', 'user.content.detail': 'content.detail',\n content_comments: 'content.comments', user_content_comments: 'content.comments', 'user.content.comments': 'content.comments',\n creator_account_stats: 'creator.account.stats', creator_content_stats: 'creator.content.stats',\n}\nexport function resolveZhihuOpenPlatformOperation(endpoint: string): ZhihuOpenPlatformOperation | undefined {\n if (Object.hasOwn(ZHIHU_OPEN_PLATFORM_APIS, endpoint)) return endpoint as ZhihuOpenPlatformOperation\n return Object.hasOwn(ENDPOINT_ALIASES, endpoint) ? ENDPOINT_ALIASES[endpoint] : undefined\n}\n\nexport type ZhihuPaging = {\n canContinue: boolean\n isEnd?: boolean\n /** Decimal Int64 string. Never synthesize this from the number of items. */\n nextOffset?: string\n warning?: string\n}\nexport type ZhihuJsonValue = string | number | boolean | null | ZhihuJsonValue[] | { [key: string]: ZhihuJsonValue }\nexport type ZhihuOpenPlatformResult = {\n version: 1\n operation: ZhihuOpenPlatformOperation\n quotaId?: ZhihuQuotaId\n /** Original Data fields. Quota's top-level array is wrapped in { Items }. */\n data: Record<string, ZhihuJsonValue>\n paging?: ZhihuPaging\n}\nexport type ZhihuPageInput = { offset?: number | string; limit?: number }\nexport type ZhihuDateInput = { startDate?: string; endDate?: string }\nexport type ZhihuCreatorContentType = 'all' | 'answer' | 'article' | 'pin' | 'zvideo'\nexport type ZhihuCommentOrder = 'score' | 'reverse' | 'ascending'\n\nconst record = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value)\n// Keep the free-form tool result compatible with the SDK's JSON value contract.\nfunction jsonValue(value: unknown): value is ZhihuJsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true\n if (typeof value === 'number') return Number.isFinite(value)\n if (Array.isArray(value)) return value.every(jsonValue)\n return record(value) && Object.values(value).every(jsonValue)\n}\nfunction jsonRecord(value: unknown): value is Record<string, ZhihuJsonValue> {\n return record(value) && Object.values(value).every(jsonValue)\n}\nfunction invalid(message: string): never { throw new ZhihuSearchError('INVALID_ARGUMENTS', message) }\n\nfunction inputObject(input: unknown): Record<string, unknown> {\n if (!record(input)) return invalid('参数必须是对象。')\n // Reject misleading identity overrides, even over raw RPC. Credentials belong to the host.\n for (const key of ['token', 'accessSecret', 'access_secret', 'accessToken', 'access_token', 'oauthToken', 'oauth_token', 'useConfiguredOauthUser', 'use_configured_oauth_user']) {\n if (Object.hasOwn(input, key)) invalid('这些接口仅使用当前 Access Secret,不接受 token 参数或 OAuth 身份切换。')\n }\n return input\n}\nfunction limit(value: unknown, fallback: number, maximum: number, name = 'limit'): string {\n const count = value === undefined ? fallback : value\n if (typeof count !== 'number' || !Number.isInteger(count) || count < 1 || count > maximum) {\n return invalid(`${name} 必须是 1-${maximum} 的整数。`)\n }\n return String(count)\n}\n\n/** Accept all nonnegative Int64 values as strings, but never accept an unsafe JS number. */\nexport function normalizeZhihuOffset(value: unknown): string {\n let decimal: string\n if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) decimal = String(value)\n else if (typeof value === 'string' && /^\\d+$/.test(value)) decimal = value.replace(/^0+(?=\\d)/, '')\n else return invalid('offset 必须是非负 Int64 整数;超过 JavaScript 安全整数范围时请用十进制字符串,不能使用不透明游标。')\n if (decimal.length > 19 || BigInt(decimal) > 9223372036854775807n) return invalid('offset 超出 Int64 范围。')\n return decimal\n}\n\nfunction zhihuUrl(value: unknown, question: boolean): string {\n if (typeof value !== 'string' || !value.trim()) return invalid(question ? 'questionUrl 不能为空。' : 'contentUrl 不能为空。')\n const cleaned = value.trim()\n if (/[\\u0000-\\u0020\\u007f\\\\]/.test(cleaned)) return invalid('知乎链接不能包含空白、控制字符或反斜线。')\n let url: URL\n try { url = new URL(cleaned) } catch { return invalid('不是有效的知乎 URL。') }\n if (url.protocol !== 'https:' || url.username || url.password || url.port) return invalid('必须使用无账号密码、无非标准端口的 HTTPS 知乎链接。')\n const valid = question\n ? url.hostname === 'www.zhihu.com' && /^\\/question\\/\\d+\\/?$/.test(url.pathname)\n : (url.hostname === 'www.zhihu.com' && /^\\/(?:answer\\/\\d+|question\\/\\d+\\/answer\\/\\d+|pin\\/\\d+|zvideo\\/\\d+)\\/?$/.test(url.pathname))\n || (url.hostname === 'zhuanlan.zhihu.com' && /^\\/p\\/\\d+\\/?$/.test(url.pathname))\n if (!valid) return invalid(question ? 'questionUrl 仅支持 https://www.zhihu.com/question/{id}。' : 'contentUrl 仅支持知乎回答、专栏文章、想法或视频链接。')\n return cleaned\n}\n\nfunction dates(input: Record<string, unknown>, params: Record<string, string>): void {\n const { startDate, endDate } = input\n if (startDate === undefined && endDate === undefined) return\n if (startDate === undefined || endDate === undefined) invalid('startDate 与 endDate 必须同时提供或同时省略。')\n for (const [key, value] of [['StartDate', startDate], ['EndDate', endDate]] as const) {\n if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) || value.slice(0, 4) === '0000') invalid(`${key} 必须是有效的 YYYY-MM-DD 公历日期。`)\n const time = new Date(`${value}T00:00:00Z`)\n if (!Number.isFinite(time.getTime()) || time.toISOString().slice(0, 10) !== value) invalid(`${key} 不是有效公历日期。`)\n params[key] = value\n }\n if (params.EndDate! < params.StartDate!) invalid('endDate 不得早于 startDate。')\n}\n\nfunction paramsFor(operation: ZhihuOpenPlatformOperation, input: Record<string, unknown>): Record<string, string> {\n const params: Record<string, string> = {}\n if (operation === 'question.recommendations') {\n // Explicit null/blank is not the same as omitting Query.\n if (input.query !== undefined) {\n if (typeof input.query !== 'string' || !input.query.trim()) invalid('主题关键词不能为空;省略 query 才会按画像推荐。')\n params.Query = input.query.trim()\n }\n params.Count = limit(input.count, 5, 20, 'count')\n } else if (operation === 'question.answers') {\n params.QuestionUrl = zhihuUrl(input.questionUrl, true)\n } else if (operation === 'content.detail' || operation === 'content.comments' || operation === 'creator.content.stats') {\n params.ContentUrl = zhihuUrl(input.contentUrl, false)\n } else if (operation === 'creator.account.stats') {\n const type = input.contentType === undefined ? 'all' : input.contentType\n if (typeof type !== 'string' || !['all', 'answer', 'article', 'pin', 'zvideo'].includes(type)) invalid('contentType 必须是 all、answer、article、pin 或 zvideo。')\n params.ContentType = type\n } else if (operation === 'quota' && input.apiIds !== undefined) {\n if (!Array.isArray(input.apiIds) || input.apiIds.some(id => typeof id !== 'string' || !(ZHIHU_QUOTA_IDS as readonly string[]).includes(id))) invalid('apiIds 包含未知官方额度项。')\n if (input.apiIds.length) params.APIIDs = [...new Set(input.apiIds)].join(',')\n }\n if (operation === 'question.answers' || operation === 'content.comments') {\n params.Offset = normalizeZhihuOffset(input.offset === undefined ? 0 : input.offset)\n params.Limit = limit(input.limit, 20, 50)\n }\n if (operation === 'content.comments') {\n const order = input.order === undefined ? 'score' : input.order\n if (typeof order !== 'string' || !['score', 'reverse', 'ascending'].includes(order)) invalid('order 必须是 score、reverse 或 ascending。')\n params.Order = order\n }\n if (operation === 'creator.account.stats' || operation === 'creator.content.stats') dates(input, params)\n return params\n}\n\nexport function normalizeZhihuPaging(data: Record<string, unknown>, offset: string): ZhihuPaging {\n const paging = data.Paging\n if (!record(paging) || typeof paging.IsEnd !== 'boolean') {\n return { canContinue: false, warning: '分页信息不完整:缺少有效的 Paging.IsEnd,请停止翻页。' }\n }\n if (paging.IsEnd) return { isEnd: true, canContinue: false }\n try {\n const nextOffset = normalizeZhihuOffset(paging.NextOffset)\n if (BigInt(nextOffset) <= BigInt(offset)) throw new Error('non-advancing offset')\n return { isEnd: false, canContinue: true, nextOffset }\n } catch {\n return { isEnd: false, canContinue: false, warning: '分页信息不完整:NextOffset 缺失、无效或未前进,请停止翻页;不要按条数计算偏移。' }\n }\n}\n\nexport async function executeZhihuOpenPlatform(\n operation: ZhihuOpenPlatformOperation,\n input: unknown = {},\n options: ZhihuClientOptions = {},\n): Promise<ZhihuOpenPlatformResult> {\n const args = inputObject(input)\n const params = paramsFor(operation, args)\n const api = ZHIHU_OPEN_PLATFORM_APIS[operation]\n const raw = await zhihuFetchJson(api.path, { params, envelope: true }, api.label, options)\n const data = operation === 'quota' && Array.isArray(raw) ? { Items: raw } : raw\n if (!jsonRecord(data)) throw new ZhihuSearchError('BAD_RESPONSE', `${api.label}的 Data 必须是 JSON 对象。`)\n return {\n version: 1, operation, data,\n ...(api.quotaId ? { quotaId: api.quotaId } : {}),\n ...(operation === 'question.answers' || operation === 'content.comments'\n ? { paging: normalizeZhihuPaging(data, params.Offset!) } : {}),\n }\n}\n\n// Typed client entry points. Authentication stays in ZhihuClientOptions, never input.\nexport const executeZhihuQuestionRecommendations = (args: { query?: string; count?: number } = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('question.recommendations', args, options)\nexport const executeZhihuQuestionAnswers = (args: { questionUrl: string } & ZhihuPageInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('question.answers', args, options)\nexport const executeZhihuUserContentDetail = (args: { contentUrl: string }, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('content.detail', args, options)\nexport const executeZhihuUserContentComments = (args: { contentUrl: string; order?: ZhihuCommentOrder } & ZhihuPageInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('content.comments', args, options)\nexport const executeZhihuCreatorAccountStats = (args: { contentType?: ZhihuCreatorContentType } & ZhihuDateInput = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('creator.account.stats', args, options)\nexport const executeZhihuCreatorContentStats = (args: { contentUrl: string } & ZhihuDateInput, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('creator.content.stats', args, options)\nexport const executeZhihuQuota = (args: { apiIds?: ZhihuQuotaId[] } = {}, options?: ZhihuClientOptions) => executeZhihuOpenPlatform('quota', args, options)\n\nexport function zhihuOpenPlatformResultCount(result: ZhihuOpenPlatformResult): number {\n if (result.operation === 'quota') return 0\n if (result.operation === 'content.detail') return typeof result.data.Body === 'string' && result.data.Body.trim() ? 1 : 0\n if (result.operation === 'creator.account.stats') return Object.keys(result.data).length ? 1 : 0\n return Array.isArray(result.data.Items) ? result.data.Items.filter(record).length : 0\n}\n"],"mappings":"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"}
|
package/lib/tools.js
CHANGED
|
@@ -48,7 +48,7 @@ function createZhihuSearchTool(options = {}) {
|
|
|
48
48
|
const { onExecuted, ...client } = options;
|
|
49
49
|
return defineTool({
|
|
50
50
|
name: ZHIHU_SEARCH_TOOL_NAME,
|
|
51
|
-
description: "
|
|
51
|
+
description: "知乎站内搜索(GET /api/v1/content/zhihu_search),取社区证据;仅作社区/读者反馈参考,不构成 canon,不写入项目文件。",
|
|
52
52
|
parameters: {
|
|
53
53
|
query: {
|
|
54
54
|
type: "string",
|
|
@@ -180,7 +180,7 @@ function createZhihuGlobalSearchTool(options = {}) {
|
|
|
180
180
|
const { onExecuted, ...client } = options;
|
|
181
181
|
return defineTool({
|
|
182
182
|
name: ZHIHU_GLOBAL_SEARCH_TOOL_NAME,
|
|
183
|
-
description: "
|
|
183
|
+
description: "知乎开放平台全网搜索(GET /api/v1/content/global_search),检索站外公开网页资料;仅作参考,不构成 canon,不写入项目文件。",
|
|
184
184
|
parameters: {
|
|
185
185
|
query: {
|
|
186
186
|
type: "string",
|
|
@@ -249,7 +249,7 @@ function createZhihuHotListTool(options = {}) {
|
|
|
249
249
|
const { onExecuted, ...client } = options;
|
|
250
250
|
return defineTool({
|
|
251
251
|
name: ZHIHU_HOT_LIST_TOOL_NAME,
|
|
252
|
-
description: "
|
|
252
|
+
description: "知乎热榜(GET /api/v1/content/hot_list),了解当前社区热点;仅作题材参考,不构成 canon,不写入项目文件。",
|
|
253
253
|
parameters: { limit: {
|
|
254
254
|
type: "integer",
|
|
255
255
|
description: `返回条数,1-30,默认 10。`
|
|
@@ -314,7 +314,7 @@ function createZhihuAskTool(options = {}) {
|
|
|
314
314
|
const { onExecuted, ...client } = options;
|
|
315
315
|
return defineTool({
|
|
316
316
|
name: ZHIHU_ASK_TOOL_NAME,
|
|
317
|
-
description: "
|
|
317
|
+
description: "知乎直答(POST /v1/chat/completions,OpenAI 兼容),基于社区内容生成综合回答,适合考据与背景调研;仅作参考,不构成 canon,不写入项目文件。",
|
|
318
318
|
parameters: {
|
|
319
319
|
query: {
|
|
320
320
|
type: "string",
|
|
@@ -377,7 +377,7 @@ function createZhihuKnowledgeSearchTool(options = {}) {
|
|
|
377
377
|
const { onExecuted, ...client } = options;
|
|
378
378
|
return defineTool({
|
|
379
379
|
name: ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,
|
|
380
|
-
description: "
|
|
380
|
+
description: "知乎知识库检索(POST /api/v1/knowledge/search,RAG 片段),默认只查公开库;网页端上传过资料后可加 personal/subscription 召回;仅作背景参考,不构成 canon,不写入项目文件。",
|
|
381
381
|
parameters: {
|
|
382
382
|
query: {
|
|
383
383
|
type: "string",
|
|
@@ -494,7 +494,7 @@ function renderZhihuOpenPlatform(result) {
|
|
|
494
494
|
notes.push("省略主题按当前账号画像推荐;条目可能少于请求数量,不支持翻页。");
|
|
495
495
|
break;
|
|
496
496
|
case "question.answers":
|
|
497
|
-
notes.push("Summary
|
|
497
|
+
notes.push("Summary 是上游摘要或截取文本,非回答全文,非额外生成的 AI 摘要。", "单页条数可能少于 Limit;Totals 可能包含被过滤的回答。只按 paging 翻页,不按条数计算偏移。");
|
|
498
498
|
break;
|
|
499
499
|
case "content.detail":
|
|
500
500
|
notes.push("仅当前 Access Secret 所属账号的已发布内容;视频仅返回关联正文,不提供视频文件。");
|
|
@@ -531,7 +531,7 @@ function renderZhihuOpenPlatform(result) {
|
|
|
531
531
|
const PAGE_PARAMETERS = {
|
|
532
532
|
offset: {
|
|
533
533
|
type: "string",
|
|
534
|
-
description: "非负 Int64 十进制字符串,默认 \"0\"
|
|
534
|
+
description: "非负 Int64 十进制字符串,默认 \"0\"。下一页只用 paging.nextOffset,不按条数推算,不接受不透明游标。"
|
|
535
535
|
},
|
|
536
536
|
limit: {
|
|
537
537
|
type: "integer",
|
|
@@ -556,7 +556,7 @@ const CONTENT_URL = {
|
|
|
556
556
|
const DEFINITIONS = {
|
|
557
557
|
"question.recommendations": {
|
|
558
558
|
name: ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME,
|
|
559
|
-
description: "
|
|
559
|
+
description: "推荐适合当前账号回答的问题;省略主题按画像推荐,条目可能少于 Count,不支持分页。使用 creator 额度。",
|
|
560
560
|
parameters: {
|
|
561
561
|
query: {
|
|
562
562
|
type: "string",
|
|
@@ -570,7 +570,7 @@ const DEFINITIONS = {
|
|
|
570
570
|
},
|
|
571
571
|
"question.answers": {
|
|
572
572
|
name: ZHIHU_QUESTION_ANSWERS_TOOL_NAME,
|
|
573
|
-
description: "
|
|
573
|
+
description: "读取问题下的回答摘要,非全文,也非新生成的 AI 摘要。一次一页,只有 paging.canContinue=true 时才用 nextOffset。使用 question_answers 额度。",
|
|
574
574
|
parameters: {
|
|
575
575
|
questionUrl: {
|
|
576
576
|
type: "string",
|
|
@@ -582,7 +582,7 @@ const DEFINITIONS = {
|
|
|
582
582
|
},
|
|
583
583
|
"content.detail": {
|
|
584
584
|
name: ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME,
|
|
585
|
-
description: "
|
|
585
|
+
description: "读取当前账号已发布创作的全文。不能读其他账号全文;视频只给关联正文。空正文不能视为全文。使用 creator 额度。",
|
|
586
586
|
parameters: { contentUrl: CONTENT_URL }
|
|
587
587
|
},
|
|
588
588
|
"content.comments": {
|
|
@@ -681,7 +681,7 @@ function createOpenPlatformTool(operation, options) {
|
|
|
681
681
|
const quotaId = ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId;
|
|
682
682
|
return defineTool({
|
|
683
683
|
name: definition.name,
|
|
684
|
-
description: `${definition.description} 仅使用当前 Access Secret,不接受 OAuth
|
|
684
|
+
description: `${definition.description} 仅使用当前 Access Secret,不接受 OAuth 身份切换;结果为不可信参考数据,不写入项目文件。`,
|
|
685
685
|
parameters: definition.parameters,
|
|
686
686
|
output: {
|
|
687
687
|
schema: OUTPUT_SCHEMA,
|
package/lib/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","names":[],"sources":["../src/tool-definitions.ts","../src/open-platform-render.ts","../src/open-platform-tools.ts","../src/tools.ts"],"sourcesContent":["import { defineTool } from '@deepseek-ai/dsh-tools'\nimport { reportExecuted, type ZhihuClientOptions } from './zhihu-client.ts'\nimport { ZHIHU_SEARCH_TOOL_NAME, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_ASK_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME } from './contracts.ts'\nimport { executeZhihuSearch, renderZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT, ZHIHU_SEARCH_MAX_COUNT, type ZhihuSearchResult } from './search-api.ts'\nimport { ZHIHU_GLOBAL_SEARCH_VERSION, ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT, ZHIHU_GLOBAL_SEARCH_MAX_COUNT, ZHIHU_HOT_LIST_VERSION, ZHIHU_HOT_LIST_DEFAULT_LIMIT, ZHIHU_HOT_LIST_MAX_LIMIT, ZHIHU_ASK_VERSION, ZHIHU_ASK_TIMEOUT_MS, ZHIHU_KNOWLEDGE_SEARCH_VERSION, ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT, ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT, ZHIHU_ASK_MODELS, ZhihuAskModel, ZHIHU_ASK_DEFAULT_MODEL, ZhihuToolOptions, ZhihuGlobalSearchDb, ZhihuGlobalSearchResult, executeZhihuGlobalSearch, renderZhihuGlobalSearch, ZhihuHotListItem, ZhihuHotListResult, executeZhihuHotList, renderZhihuHotList, ZhihuAskResult, executeZhihuAsk, renderZhihuAsk, ZhihuKnowledgeItem, ZhihuRecallScope, ZHIHU_RECALL_SCOPES, ZhihuKnowledgeSearchResult, normalizeRecallScopes, executeZhihuKnowledgeSearch, renderZhihuKnowledgeSearch } from './operations.ts'\nexport type CreateZhihuSearchToolOptions = ZhihuClientOptions & {\n /** Best-effort metering hook; invoked after every execution, failures included. */\n onExecuted?: (event: { ok: boolean; results: number }) => void\n}\n\nconst SEARCH_ITEM_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n type: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n votes: { type: 'integer', required: true },\n comments: { type: 'integer', required: true },\n author: { type: 'string', required: true },\n authority: { type: 'string', required: true },\n editTime: { type: 'string', required: true },\n },\n} as const\n\nexport function createZhihuSearchTool(options: CreateZhihuSearchToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_SEARCH_TOOL_NAME,\n description: '调用知乎开放平台站内搜索(GET /api/v1/content/zhihu_search)拉取社区证据;结果仅作社区/读者反馈参考,不构成 canon,也不直接写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '搜索词,2-100 字符。' },\n count: { type: 'integer', description: `返回条数,1-${ZHIHU_SEARCH_MAX_COUNT},默认 ${ZHIHU_SEARCH_DEFAULT_COUNT}。` },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n count: { type: 'integer', required: true },\n items: {\n type: 'array',\n required: true,\n items: SEARCH_ITEM_SCHEMA,\n },\n emptyReason: { type: 'string' },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuSearch(value as ZhihuSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; count?: number }\n try {\n const result = await executeZhihuSearch(typed.query, typed.count ?? ZHIHU_SEARCH_DEFAULT_COUNT, {\n ...client,\n signal: exec.signal,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n return result\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n })\n}\n\nconst OTHER_SEARCH_ITEM_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n type: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n votes: { type: 'integer', required: true },\n comments: { type: 'integer', required: true },\n author: { type: 'string', required: true },\n authority: { type: 'string', required: true },\n editTime: { type: 'string', required: true },\n },\n} as const\n\n/** 包一层计量:成功报 results,失败报 ok:false 再原样抛出。 */\nasync function metered<T>(onExecuted: ZhihuToolOptions['onExecuted'], run: () => Promise<T>, results: (value: T) => number): Promise<T> {\n try {\n const value = await run()\n reportExecuted(onExecuted, { ok: true, results: results(value) })\n return value\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n}\n\nexport function createZhihuGlobalSearchTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_GLOBAL_SEARCH_TOOL_NAME,\n description: '调用知乎开放平台全网搜索(GET /api/v1/content/global_search)检索站外公开网页资料;结果仅作参考,不构成 canon,也不直接写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '搜索词,2-100 字符。' },\n count: { type: 'integer', description: `返回条数,1-${ZHIHU_GLOBAL_SEARCH_MAX_COUNT},默认 ${ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT}。` },\n searchDb: { type: 'string', description: '检索库:all(默认)、realtime(实时)、static(静态)。' },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n count: { type: 'integer', required: true },\n searchDb: { type: 'string', required: true },\n items: { type: 'array', required: true, items: OTHER_SEARCH_ITEM_SCHEMA },\n emptyReason: { type: 'string' },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuGlobalSearch(value as ZhihuGlobalSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; count?: number; searchDb?: string }\n const searchDb: ZhihuGlobalSearchDb = typed.searchDb === 'realtime' || typed.searchDb === 'static' ? typed.searchDb : 'all'\n return await metered(onExecuted, () => executeZhihuGlobalSearch(\n typed.query,\n typed.count ?? ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT,\n searchDb,\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n\nexport function createZhihuHotListTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_HOT_LIST_TOOL_NAME,\n description: '拉取知乎热榜(GET /api/v1/content/hot_list)了解当前社区热点;结果仅作题材与热点参考,不构成 canon,也不直接写入项目文件。',\n parameters: {\n limit: { type: 'integer', description: `返回条数,1-${ZHIHU_HOT_LIST_MAX_LIMIT},默认 ${ZHIHU_HOT_LIST_DEFAULT_LIMIT}。` },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n limit: { type: 'integer', required: true },\n items: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n },\n },\n },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuHotList(value as ZhihuHotListResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { limit?: number }\n return await metered(onExecuted, () => executeZhihuHotList(\n typed.limit ?? ZHIHU_HOT_LIST_DEFAULT_LIMIT,\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n\nexport function createZhihuAskTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_ASK_TOOL_NAME,\n description: '调用知乎直答(POST /v1/chat/completions,OpenAI 兼容)基于知乎社区内容生成综合回答;适合考据与背景调研。结果仅作参考,不构成 canon,也不直接写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '要问的问题。' },\n model: { type: 'string', description: 'zhida-thinking-1p5(默认,带思考过程)、zhida-fast-1p5(快,仅适合简单事实查询)或 zhida-agent(最慢最强,仅在明确要求时使用)。' },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n model: { type: 'string', required: true },\n content: { type: 'string', required: true },\n reasoning: { type: 'string', required: true },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuAsk(value as ZhihuAskResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; model?: string }\n const model: ZhihuAskModel = (ZHIHU_ASK_MODELS as readonly string[]).includes(typed.model ?? '')\n ? (typed.model as ZhihuAskModel)\n : ZHIHU_ASK_DEFAULT_MODEL\n return await metered(onExecuted, () => executeZhihuAsk(\n typed.query,\n model,\n { ...client, signal: exec.signal },\n ), (result) => (result.content ? 1 : 0))\n },\n })\n}\n\nexport function createZhihuKnowledgeSearchTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,\n description: '检索知乎知识库(POST /api/v1/knowledge/search,RAG 片段),默认只查公开库;用户在知乎网页端上传过个人资料后可加 personal/subscription 召回。结果仅作背景参考,不构成 canon,也不直接写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '检索词。' },\n limit: { type: 'integer', description: `返回条数,1-${ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT},默认 ${ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT}。` },\n recallScopes: {\n type: 'array',\n description: '召回范围:public(公开库,默认)、personal(个人库)、subscription(订阅库),可多选。',\n items: { type: 'string', enum: [...ZHIHU_RECALL_SCOPES] },\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n limit: { type: 'integer', required: true },\n recallScopes: { type: 'array', required: true, items: { type: 'string' } },\n items: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n docName: { type: 'string', required: true },\n originUrl: { type: 'string', required: true },\n snippets: { type: 'array', required: true, items: { type: 'string' } },\n },\n },\n },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuKnowledgeSearch(value as ZhihuKnowledgeSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; limit?: number; recallScopes?: unknown }\n return await metered(onExecuted, () => executeZhihuKnowledgeSearch(\n typed.query,\n typed.limit ?? ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT,\n normalizeRecallScopes(typed.recallScopes),\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n","import { ZHIHU_OPEN_PLATFORM_APIS, type ZhihuOpenPlatformResult } from './open-platform.ts'\n\n/** Display only: the structured result always retains the original upstream HTML. */\nexport function plainZhihuText(value: string): string {\n const entities: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ' }\n const decoded = value.replace(/&(#x[\\da-f]+|#\\d+|amp|lt|gt|quot|apos|nbsp);/gi, (match, entity: string) => {\n if (!entity.startsWith('#')) return entities[entity.toLowerCase()] ?? match\n const hex = entity[1]?.toLowerCase() === 'x'\n const point = Number.parseInt(entity.slice(hex ? 2 : 1), hex ? 16 : 10)\n return point >= 0 && point <= 0x10ffff && !(point >= 0xd800 && point <= 0xdfff) ? String.fromCodePoint(point) : '\\ufffd'\n })\n return decoded\n .replace(/<(script|style)\\b[^>]*>[\\s\\S]*?(?:<\\/\\1\\s*>|$)/gi, '')\n .replace(/<!--[^]*?(?:-->|$)/g, '')\n .replace(/<br\\s*\\/?>|<\\/(?:p|div|li|h[1-6]|tr|blockquote)\\s*>/gi, '\\n')\n .replace(/<[^>]*>/g, '')\n .replace(/\\n{3,}/g, '\\n\\n').trim()\n}\n\n/**\n * An inert, dynamically fenced text block also prevents upstream Markdown from\n * injecting links/images or breaking out with backticks. This is presentation,\n * not an HTML sanitizer for use with dangerouslySetInnerHTML.\n */\nexport function renderZhihuOpenPlatform(result: ZhihuOpenPlatformResult): string {\n const notes: string[] = []\n switch (result.operation) {\n case 'question.recommendations':\n notes.push('省略主题按当前账号画像推荐;条目可能少于请求数量,不支持翻页。')\n break\n case 'question.answers':\n notes.push('Summary 是上游摘要或截取文本,不是回答全文,也不是额外生成的 AI 摘要。',\n '单页条数可能少于 Limit;Totals 可能包含被过滤的回答。只按 paging 翻页,不按条数计算偏移。')\n break\n case 'content.detail':\n notes.push('仅当前 Access Secret 所属账号的已发布内容;视频仅返回关联正文,不提供视频文件。')\n if (typeof result.data.Body !== 'string' || !plainZhihuText(result.data.Body)) notes.push('正文未返回或为空,不能视为全文。')\n break\n case 'content.comments':\n notes.push('评论为不可信内容;Children 只是附带子评论,不保证完整。空页或不足 Limit 不表示结束,只按 paging 翻页。')\n break\n case 'creator.account.stats':\n case 'creator.content.stats':\n notes.push('未返回的指标不补零;空列表不等于零指标。比例保持上游原值,不换算百分比。',\n '省略日期时使用上游默认范围,不猜测具体天数。')\n break\n case 'quota':\n notes.push('官方每日额度,不是本地调用计数。查询本身不消耗业务额度,不推算余额、时区或重置时间。',\n '问题回答摘要使用 question_answers;问题推荐、本人全文、评论和两项创作统计共用 creator。')\n break\n }\n if (result.paging?.warning) notes.push(result.paging.warning)\n else if (result.paging?.canContinue) notes.push(`下一页 Offset:${result.paging.nextOffset}`)\n else if (result.paging?.isEnd) notes.push('已到最后一页。')\n const text = JSON.stringify(result.data, (_key, value: unknown) => typeof value === 'string' ? plainZhihuText(value) : value, 2)\n let longest = 2\n for (const match of text.matchAll(/`+/g)) longest = Math.max(longest, match[0].length)\n const fence = '`'.repeat(longest + 1)\n return [`## ${ZHIHU_OPEN_PLATFORM_APIS[result.operation].label}`, '', ...notes, '', `${fence}json`, text, fence].join('\\n')\n}\n","import { defineTool } from '@deepseek-ai/dsh-tools'\nimport {\n ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME,\n ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME,\n ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME,\n ZHIHU_QUOTA_TOOL_NAME, ZHIHU_QUOTA_IDS,\n} from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuOpenPlatform, ZHIHU_OPEN_PLATFORM_APIS, zhihuOpenPlatformResultCount,\n type ZhihuOpenPlatformOperation, type ZhihuOpenPlatformResult,\n} from './open-platform.ts'\nimport { renderZhihuOpenPlatform } from './open-platform-render.ts'\n\nexport type ZhihuOpenPlatformToolOptions = ZhihuClientOptions & { onExecuted?: (event: ZhihuSearchExecuted) => void }\nconst PAGE_PARAMETERS = {\n offset: { type: 'string', description: '非负 Int64 十进制字符串,默认 \"0\"。下一页只使用 paging.nextOffset;不可按条数计算,不接受不透明游标。' },\n limit: { type: 'integer', description: '每页数量,1-50,默认 20。单页不足或为空不表示结束。' },\n} as const\nconst DATE_PARAMETERS = {\n startDate: { type: 'string', description: 'YYYY-MM-DD,必须与 endDate 同时提供。省略两者使用上游默认范围,不猜测天数。' },\n endDate: { type: 'string', description: 'YYYY-MM-DD,不得早于 startDate。' },\n} as const\nconst CONTENT_URL = { type: 'string', required: true, description: '当前账号已发布内容的 HTTPS 知乎回答、专栏文章、想法或视频链接;不是任意网页抓取。' } as const\n\nconst DEFINITIONS = {\n 'question.recommendations': {\n name: ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME,\n description: '推荐适合当前账号回答的问题。省略主题按画像推荐;条目可能少于 Count,不支持分页。使用 creator 额度。',\n parameters: {\n query: { type: 'string', description: '可选主题;不传才按画像推荐,空白字符串无效。' },\n count: { type: 'integer', description: '推荐数量,1-20,默认 5。' },\n },\n },\n 'question.answers': {\n name: ZHIHU_QUESTION_ANSWERS_TOOL_NAME,\n description: '读取问题下的回答摘要,不是全文,也不是新生成的 AI 摘要。一次一页,只有 paging.canContinue=true 时可使用 nextOffset。使用 question_answers 额度。',\n parameters: {\n questionUrl: { type: 'string', required: true, description: 'https://www.zhihu.com/question/{id} 形式的问题链接。' },\n ...PAGE_PARAMETERS,\n },\n },\n 'content.detail': {\n name: ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME,\n description: '读取当前账号已发布创作的全文。不能读取其他账号全文;视频只提供关联正文。空正文不能视为全文。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL },\n },\n 'content.comments': {\n name: ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME,\n description: '读取当前账号创作下的根评论及附带 Children;子评论不保证完整。一次一页,只按 paging 翻页,不按条数判断结束。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL, ...PAGE_PARAMETERS, order: { type: 'string', enum: ['score', 'reverse', 'ascending'], description: '排序,默认 score。' } },\n },\n 'creator.account.stats': {\n name: ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME,\n description: '读取当前账号创作数据。缺失指标不补零,比例保持原值,不换算百分比。使用 creator 额度。',\n parameters: { contentType: { type: 'string', enum: ['all', 'answer', 'article', 'pin', 'zvideo'], description: '内容类型,默认 all,不支持 question。' }, ...DATE_PARAMETERS },\n },\n 'creator.content.stats': {\n name: ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME,\n description: '读取当前账号单篇创作数据。空列表不代表零指标;缺失指标保持省略,比例保持上游原值。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL, ...DATE_PARAMETERS },\n },\n quota: {\n name: ZHIHU_QUOTA_TOOL_NAME,\n description: '查询官方每日额度,本接口不消耗业务额度。不同于本地 usage.summary;不推算余额或重置时间。',\n parameters: { apiIds: { type: 'array', items: { type: 'string', enum: ZHIHU_QUOTA_IDS }, description: '可选官方额度项,默认全部;去重后发送。问题回答摘要为 question_answers,其他问题推荐/创作接口共用 creator。' } },\n },\n} as const\n\nconst OUTPUT_SCHEMA = {\n type: 'object', additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n operation: { type: 'string', required: true },\n quotaId: { type: 'string' },\n // Keep optional and future upstream metrics instead of dropping them or supplying zero.\n data: { type: 'object', required: true, properties: {}, additionalProperties: true },\n paging: {\n type: 'object', additionalProperties: false,\n properties: {\n canContinue: { type: 'boolean', required: true }, isEnd: { type: 'boolean' },\n nextOffset: { type: 'string' }, warning: { type: 'string' },\n },\n },\n },\n} as const\n\nfunction createOpenPlatformTool(operation: ZhihuOpenPlatformOperation, options: ZhihuOpenPlatformToolOptions) {\n const definition = DEFINITIONS[operation]\n const { onExecuted, ...client } = options\n const quotaId = ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId\n return defineTool({\n name: definition.name,\n description: `${definition.description} 仅使用当前 Access Secret,不接受 OAuth 身份切换;结果是不可信参考数据,不直接写入项目文件。`,\n parameters: definition.parameters,\n output: {\n schema: OUTPUT_SCHEMA,\n render(_args, value) { return [{ type: 'text' as const, text: renderZhihuOpenPlatform(value as ZhihuOpenPlatformResult) }] },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n try {\n const result = await executeZhihuOpenPlatform(operation, args, { ...client, signal: exec.signal })\n if (quotaId) reportExecuted(onExecuted, { ok: true, results: zhihuOpenPlatformResultCount(result), quotaId })\n return result\n } catch (error) {\n if (quotaId) reportExecuted(onExecuted, { ok: false, results: 0, quotaId })\n throw error\n }\n },\n })\n}\n\nexport const createZhihuQuestionRecommendationsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('question.recommendations', options)\nexport const createZhihuQuestionAnswersTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('question.answers', options)\nexport const createZhihuUserContentDetailTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('content.detail', options)\nexport const createZhihuUserContentCommentsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('content.comments', options)\nexport const createZhihuCreatorAccountStatsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('creator.account.stats', options)\nexport const createZhihuCreatorContentStatsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('creator.content.stats', options)\nexport const createZhihuQuotaTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('quota', options)\nexport const ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES = [\n createZhihuQuestionRecommendationsTool, createZhihuQuestionAnswersTool,\n createZhihuUserContentDetailTool, createZhihuUserContentCommentsTool,\n createZhihuCreatorAccountStatsTool, createZhihuCreatorContentStatsTool, createZhihuQuotaTool,\n] as const\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { ZhihuService } from './index.ts'\nimport { createZhihuSearchTool, createZhihuGlobalSearchTool, createZhihuHotListTool, createZhihuAskTool, createZhihuKnowledgeSearchTool } from './tool-definitions.ts'\nimport { ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES } from './open-platform-tools.ts'\nexport const name = 'dsh-zhihu-tools'\nexport const inject = ['zhihu', 'tools'] as const\nexport function apply(ctx: Context): void {\n const host = ctx as Context & { zhihu: ZhihuService; tools: { register: (tool: unknown) => unknown } }\n const options = host.zhihu.toolOptions\n for (const create of [createZhihuSearchTool, createZhihuGlobalSearchTool, createZhihuHotListTool, createZhihuAskTool, createZhihuKnowledgeSearchTool, ...ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES]) {\n const tool = create(options)\n const execute = tool.execute as unknown as (args: unknown, exec: { signal: AbortSignal }) => Promise<unknown>\n host.tools.register({ ...tool, execute: (args: unknown, exec: { signal: AbortSignal }) =>\n host.zhihu.run(signal => execute(args, { ...exec, signal }), exec.signal) })\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tools.js","names":[],"sources":["../src/tool-definitions.ts","../src/open-platform-render.ts","../src/open-platform-tools.ts","../src/tools.ts"],"sourcesContent":["import { defineTool } from '@deepseek-ai/dsh-tools'\nimport { reportExecuted, type ZhihuClientOptions } from './zhihu-client.ts'\nimport { ZHIHU_SEARCH_TOOL_NAME, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_ASK_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME } from './contracts.ts'\nimport { executeZhihuSearch, renderZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT, ZHIHU_SEARCH_MAX_COUNT, type ZhihuSearchResult } from './search-api.ts'\nimport { ZHIHU_GLOBAL_SEARCH_VERSION, ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT, ZHIHU_GLOBAL_SEARCH_MAX_COUNT, ZHIHU_HOT_LIST_VERSION, ZHIHU_HOT_LIST_DEFAULT_LIMIT, ZHIHU_HOT_LIST_MAX_LIMIT, ZHIHU_ASK_VERSION, ZHIHU_ASK_TIMEOUT_MS, ZHIHU_KNOWLEDGE_SEARCH_VERSION, ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT, ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT, ZHIHU_ASK_MODELS, ZhihuAskModel, ZHIHU_ASK_DEFAULT_MODEL, ZhihuToolOptions, ZhihuGlobalSearchDb, ZhihuGlobalSearchResult, executeZhihuGlobalSearch, renderZhihuGlobalSearch, ZhihuHotListItem, ZhihuHotListResult, executeZhihuHotList, renderZhihuHotList, ZhihuAskResult, executeZhihuAsk, renderZhihuAsk, ZhihuKnowledgeItem, ZhihuRecallScope, ZHIHU_RECALL_SCOPES, ZhihuKnowledgeSearchResult, normalizeRecallScopes, executeZhihuKnowledgeSearch, renderZhihuKnowledgeSearch } from './operations.ts'\nexport type CreateZhihuSearchToolOptions = ZhihuClientOptions & {\n /** Best-effort metering hook; invoked after every execution, failures included. */\n onExecuted?: (event: { ok: boolean; results: number }) => void\n}\n\nconst SEARCH_ITEM_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n type: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n votes: { type: 'integer', required: true },\n comments: { type: 'integer', required: true },\n author: { type: 'string', required: true },\n authority: { type: 'string', required: true },\n editTime: { type: 'string', required: true },\n },\n} as const\n\nexport function createZhihuSearchTool(options: CreateZhihuSearchToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_SEARCH_TOOL_NAME,\n description: '知乎站内搜索(GET /api/v1/content/zhihu_search),取社区证据;仅作社区/读者反馈参考,不构成 canon,不写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '搜索词,2-100 字符。' },\n count: { type: 'integer', description: `返回条数,1-${ZHIHU_SEARCH_MAX_COUNT},默认 ${ZHIHU_SEARCH_DEFAULT_COUNT}。` },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n count: { type: 'integer', required: true },\n items: {\n type: 'array',\n required: true,\n items: SEARCH_ITEM_SCHEMA,\n },\n emptyReason: { type: 'string' },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuSearch(value as ZhihuSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; count?: number }\n try {\n const result = await executeZhihuSearch(typed.query, typed.count ?? ZHIHU_SEARCH_DEFAULT_COUNT, {\n ...client,\n signal: exec.signal,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n return result\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n })\n}\n\nconst OTHER_SEARCH_ITEM_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n type: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n votes: { type: 'integer', required: true },\n comments: { type: 'integer', required: true },\n author: { type: 'string', required: true },\n authority: { type: 'string', required: true },\n editTime: { type: 'string', required: true },\n },\n} as const\n\n/** 包一层计量:成功报 results,失败报 ok:false 再原样抛出。 */\nasync function metered<T>(onExecuted: ZhihuToolOptions['onExecuted'], run: () => Promise<T>, results: (value: T) => number): Promise<T> {\n try {\n const value = await run()\n reportExecuted(onExecuted, { ok: true, results: results(value) })\n return value\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n}\n\nexport function createZhihuGlobalSearchTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_GLOBAL_SEARCH_TOOL_NAME,\n description: '知乎开放平台全网搜索(GET /api/v1/content/global_search),检索站外公开网页资料;仅作参考,不构成 canon,不写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '搜索词,2-100 字符。' },\n count: { type: 'integer', description: `返回条数,1-${ZHIHU_GLOBAL_SEARCH_MAX_COUNT},默认 ${ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT}。` },\n searchDb: { type: 'string', description: '检索库:all(默认)、realtime(实时)、static(静态)。' },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n count: { type: 'integer', required: true },\n searchDb: { type: 'string', required: true },\n items: { type: 'array', required: true, items: OTHER_SEARCH_ITEM_SCHEMA },\n emptyReason: { type: 'string' },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuGlobalSearch(value as ZhihuGlobalSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; count?: number; searchDb?: string }\n const searchDb: ZhihuGlobalSearchDb = typed.searchDb === 'realtime' || typed.searchDb === 'static' ? typed.searchDb : 'all'\n return await metered(onExecuted, () => executeZhihuGlobalSearch(\n typed.query,\n typed.count ?? ZHIHU_GLOBAL_SEARCH_DEFAULT_COUNT,\n searchDb,\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n\nexport function createZhihuHotListTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_HOT_LIST_TOOL_NAME,\n description: '知乎热榜(GET /api/v1/content/hot_list),了解当前社区热点;仅作题材参考,不构成 canon,不写入项目文件。',\n parameters: {\n limit: { type: 'integer', description: `返回条数,1-${ZHIHU_HOT_LIST_MAX_LIMIT},默认 ${ZHIHU_HOT_LIST_DEFAULT_LIMIT}。` },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n limit: { type: 'integer', required: true },\n items: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', required: true },\n url: { type: 'string', required: true },\n summary: { type: 'string', required: true },\n },\n },\n },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuHotList(value as ZhihuHotListResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { limit?: number }\n return await metered(onExecuted, () => executeZhihuHotList(\n typed.limit ?? ZHIHU_HOT_LIST_DEFAULT_LIMIT,\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n\nexport function createZhihuAskTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_ASK_TOOL_NAME,\n description: '知乎直答(POST /v1/chat/completions,OpenAI 兼容),基于社区内容生成综合回答,适合考据与背景调研;仅作参考,不构成 canon,不写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '要问的问题。' },\n model: { type: 'string', description: 'zhida-thinking-1p5(默认,带思考过程)、zhida-fast-1p5(快,仅适合简单事实查询)或 zhida-agent(最慢最强,仅在明确要求时使用)。' },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n model: { type: 'string', required: true },\n content: { type: 'string', required: true },\n reasoning: { type: 'string', required: true },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuAsk(value as ZhihuAskResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; model?: string }\n const model: ZhihuAskModel = (ZHIHU_ASK_MODELS as readonly string[]).includes(typed.model ?? '')\n ? (typed.model as ZhihuAskModel)\n : ZHIHU_ASK_DEFAULT_MODEL\n return await metered(onExecuted, () => executeZhihuAsk(\n typed.query,\n model,\n { ...client, signal: exec.signal },\n ), (result) => (result.content ? 1 : 0))\n },\n })\n}\n\nexport function createZhihuKnowledgeSearchTool(options: ZhihuToolOptions = {}) {\n const { onExecuted, ...client } = options\n return defineTool({\n name: ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,\n description: '知乎知识库检索(POST /api/v1/knowledge/search,RAG 片段),默认只查公开库;网页端上传过资料后可加 personal/subscription 召回;仅作背景参考,不构成 canon,不写入项目文件。',\n parameters: {\n query: { type: 'string', required: true, description: '检索词。' },\n limit: { type: 'integer', description: `返回条数,1-${ZHIHU_KNOWLEDGE_SEARCH_MAX_LIMIT},默认 ${ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT}。` },\n recallScopes: {\n type: 'array',\n description: '召回范围:public(公开库,默认)、personal(个人库)、subscription(订阅库),可多选。',\n items: { type: 'string', enum: [...ZHIHU_RECALL_SCOPES] },\n },\n },\n output: {\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n query: { type: 'string', required: true },\n limit: { type: 'integer', required: true },\n recallScopes: { type: 'array', required: true, items: { type: 'string' } },\n items: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n docName: { type: 'string', required: true },\n originUrl: { type: 'string', required: true },\n snippets: { type: 'array', required: true, items: { type: 'string' } },\n },\n },\n },\n },\n },\n render(_args, value) {\n return [{ type: 'text' as const, text: renderZhihuKnowledgeSearch(value as ZhihuKnowledgeSearchResult) }]\n },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n const typed = args as { query: string; limit?: number; recallScopes?: unknown }\n return await metered(onExecuted, () => executeZhihuKnowledgeSearch(\n typed.query,\n typed.limit ?? ZHIHU_KNOWLEDGE_SEARCH_DEFAULT_LIMIT,\n normalizeRecallScopes(typed.recallScopes),\n { ...client, signal: exec.signal },\n ), (result) => result.items.length)\n },\n })\n}\n","import { ZHIHU_OPEN_PLATFORM_APIS, type ZhihuOpenPlatformResult } from './open-platform.ts'\n\n/** Display only: the structured result always retains the original upstream HTML. */\nexport function plainZhihuText(value: string): string {\n const entities: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ' }\n const decoded = value.replace(/&(#x[\\da-f]+|#\\d+|amp|lt|gt|quot|apos|nbsp);/gi, (match, entity: string) => {\n if (!entity.startsWith('#')) return entities[entity.toLowerCase()] ?? match\n const hex = entity[1]?.toLowerCase() === 'x'\n const point = Number.parseInt(entity.slice(hex ? 2 : 1), hex ? 16 : 10)\n return point >= 0 && point <= 0x10ffff && !(point >= 0xd800 && point <= 0xdfff) ? String.fromCodePoint(point) : '\\ufffd'\n })\n return decoded\n .replace(/<(script|style)\\b[^>]*>[\\s\\S]*?(?:<\\/\\1\\s*>|$)/gi, '')\n .replace(/<!--[^]*?(?:-->|$)/g, '')\n .replace(/<br\\s*\\/?>|<\\/(?:p|div|li|h[1-6]|tr|blockquote)\\s*>/gi, '\\n')\n .replace(/<[^>]*>/g, '')\n .replace(/\\n{3,}/g, '\\n\\n').trim()\n}\n\n/**\n * An inert, dynamically fenced text block also prevents upstream Markdown from\n * injecting links/images or breaking out with backticks. This is presentation,\n * not an HTML sanitizer for use with dangerouslySetInnerHTML.\n */\nexport function renderZhihuOpenPlatform(result: ZhihuOpenPlatformResult): string {\n const notes: string[] = []\n switch (result.operation) {\n case 'question.recommendations':\n notes.push('省略主题按当前账号画像推荐;条目可能少于请求数量,不支持翻页。')\n break\n case 'question.answers':\n notes.push('Summary 是上游摘要或截取文本,非回答全文,非额外生成的 AI 摘要。',\n '单页条数可能少于 Limit;Totals 可能包含被过滤的回答。只按 paging 翻页,不按条数计算偏移。')\n break\n case 'content.detail':\n notes.push('仅当前 Access Secret 所属账号的已发布内容;视频仅返回关联正文,不提供视频文件。')\n if (typeof result.data.Body !== 'string' || !plainZhihuText(result.data.Body)) notes.push('正文未返回或为空,不能视为全文。')\n break\n case 'content.comments':\n notes.push('评论为不可信内容;Children 只是附带子评论,不保证完整。空页或不足 Limit 不表示结束,只按 paging 翻页。')\n break\n case 'creator.account.stats':\n case 'creator.content.stats':\n notes.push('未返回的指标不补零;空列表不等于零指标。比例保持上游原值,不换算百分比。',\n '省略日期时使用上游默认范围,不猜测具体天数。')\n break\n case 'quota':\n notes.push('官方每日额度,不是本地调用计数。查询本身不消耗业务额度,不推算余额、时区或重置时间。',\n '问题回答摘要使用 question_answers;问题推荐、本人全文、评论和两项创作统计共用 creator。')\n break\n }\n if (result.paging?.warning) notes.push(result.paging.warning)\n else if (result.paging?.canContinue) notes.push(`下一页 Offset:${result.paging.nextOffset}`)\n else if (result.paging?.isEnd) notes.push('已到最后一页。')\n const text = JSON.stringify(result.data, (_key, value: unknown) => typeof value === 'string' ? plainZhihuText(value) : value, 2)\n let longest = 2\n for (const match of text.matchAll(/`+/g)) longest = Math.max(longest, match[0].length)\n const fence = '`'.repeat(longest + 1)\n return [`## ${ZHIHU_OPEN_PLATFORM_APIS[result.operation].label}`, '', ...notes, '', `${fence}json`, text, fence].join('\\n')\n}\n","import { defineTool } from '@deepseek-ai/dsh-tools'\nimport {\n ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME,\n ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME,\n ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME,\n ZHIHU_QUOTA_TOOL_NAME, ZHIHU_QUOTA_IDS,\n} from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuOpenPlatform, ZHIHU_OPEN_PLATFORM_APIS, zhihuOpenPlatformResultCount,\n type ZhihuOpenPlatformOperation, type ZhihuOpenPlatformResult,\n} from './open-platform.ts'\nimport { renderZhihuOpenPlatform } from './open-platform-render.ts'\n\nexport type ZhihuOpenPlatformToolOptions = ZhihuClientOptions & { onExecuted?: (event: ZhihuSearchExecuted) => void }\nconst PAGE_PARAMETERS = {\n offset: { type: 'string', description: '非负 Int64 十进制字符串,默认 \"0\"。下一页只用 paging.nextOffset,不按条数推算,不接受不透明游标。' },\n limit: { type: 'integer', description: '每页数量,1-50,默认 20。单页不足或为空不表示结束。' },\n} as const\nconst DATE_PARAMETERS = {\n startDate: { type: 'string', description: 'YYYY-MM-DD,必须与 endDate 同时提供。省略两者使用上游默认范围,不猜测天数。' },\n endDate: { type: 'string', description: 'YYYY-MM-DD,不得早于 startDate。' },\n} as const\nconst CONTENT_URL = { type: 'string', required: true, description: '当前账号已发布内容的 HTTPS 知乎回答、专栏文章、想法或视频链接;不是任意网页抓取。' } as const\n\nconst DEFINITIONS = {\n 'question.recommendations': {\n name: ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME,\n description: '推荐适合当前账号回答的问题;省略主题按画像推荐,条目可能少于 Count,不支持分页。使用 creator 额度。',\n parameters: {\n query: { type: 'string', description: '可选主题;不传才按画像推荐,空白字符串无效。' },\n count: { type: 'integer', description: '推荐数量,1-20,默认 5。' },\n },\n },\n 'question.answers': {\n name: ZHIHU_QUESTION_ANSWERS_TOOL_NAME,\n description: '读取问题下的回答摘要,非全文,也非新生成的 AI 摘要。一次一页,只有 paging.canContinue=true 时才用 nextOffset。使用 question_answers 额度。',\n parameters: {\n questionUrl: { type: 'string', required: true, description: 'https://www.zhihu.com/question/{id} 形式的问题链接。' },\n ...PAGE_PARAMETERS,\n },\n },\n 'content.detail': {\n name: ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME,\n description: '读取当前账号已发布创作的全文。不能读其他账号全文;视频只给关联正文。空正文不能视为全文。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL },\n },\n 'content.comments': {\n name: ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME,\n description: '读取当前账号创作下的根评论及附带 Children;子评论不保证完整。一次一页,只按 paging 翻页,不按条数判断结束。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL, ...PAGE_PARAMETERS, order: { type: 'string', enum: ['score', 'reverse', 'ascending'], description: '排序,默认 score。' } },\n },\n 'creator.account.stats': {\n name: ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME,\n description: '读取当前账号创作数据。缺失指标不补零,比例保持原值,不换算百分比。使用 creator 额度。',\n parameters: { contentType: { type: 'string', enum: ['all', 'answer', 'article', 'pin', 'zvideo'], description: '内容类型,默认 all,不支持 question。' }, ...DATE_PARAMETERS },\n },\n 'creator.content.stats': {\n name: ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME,\n description: '读取当前账号单篇创作数据。空列表不代表零指标;缺失指标保持省略,比例保持上游原值。使用 creator 额度。',\n parameters: { contentUrl: CONTENT_URL, ...DATE_PARAMETERS },\n },\n quota: {\n name: ZHIHU_QUOTA_TOOL_NAME,\n description: '查询官方每日额度,本接口不消耗业务额度。不同于本地 usage.summary;不推算余额或重置时间。',\n parameters: { apiIds: { type: 'array', items: { type: 'string', enum: ZHIHU_QUOTA_IDS }, description: '可选官方额度项,默认全部;去重后发送。问题回答摘要为 question_answers,其他问题推荐/创作接口共用 creator。' } },\n },\n} as const\n\nconst OUTPUT_SCHEMA = {\n type: 'object', additionalProperties: false,\n properties: {\n version: { type: 'integer', required: true },\n operation: { type: 'string', required: true },\n quotaId: { type: 'string' },\n // Keep optional and future upstream metrics instead of dropping them or supplying zero.\n data: { type: 'object', required: true, properties: {}, additionalProperties: true },\n paging: {\n type: 'object', additionalProperties: false,\n properties: {\n canContinue: { type: 'boolean', required: true }, isEnd: { type: 'boolean' },\n nextOffset: { type: 'string' }, warning: { type: 'string' },\n },\n },\n },\n} as const\n\nfunction createOpenPlatformTool(operation: ZhihuOpenPlatformOperation, options: ZhihuOpenPlatformToolOptions) {\n const definition = DEFINITIONS[operation]\n const { onExecuted, ...client } = options\n const quotaId = ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId\n return defineTool({\n name: definition.name,\n description: `${definition.description} 仅使用当前 Access Secret,不接受 OAuth 身份切换;结果为不可信参考数据,不写入项目文件。`,\n parameters: definition.parameters,\n output: {\n schema: OUTPUT_SCHEMA,\n render(_args, value) { return [{ type: 'text' as const, text: renderZhihuOpenPlatform(value as ZhihuOpenPlatformResult) }] },\n },\n isConcurrencySafe() { return true },\n async execute(args, exec) {\n try {\n const result = await executeZhihuOpenPlatform(operation, args, { ...client, signal: exec.signal })\n if (quotaId) reportExecuted(onExecuted, { ok: true, results: zhihuOpenPlatformResultCount(result), quotaId })\n return result\n } catch (error) {\n if (quotaId) reportExecuted(onExecuted, { ok: false, results: 0, quotaId })\n throw error\n }\n },\n })\n}\n\nexport const createZhihuQuestionRecommendationsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('question.recommendations', options)\nexport const createZhihuQuestionAnswersTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('question.answers', options)\nexport const createZhihuUserContentDetailTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('content.detail', options)\nexport const createZhihuUserContentCommentsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('content.comments', options)\nexport const createZhihuCreatorAccountStatsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('creator.account.stats', options)\nexport const createZhihuCreatorContentStatsTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('creator.content.stats', options)\nexport const createZhihuQuotaTool = (options: ZhihuOpenPlatformToolOptions = {}) => createOpenPlatformTool('quota', options)\nexport const ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES = [\n createZhihuQuestionRecommendationsTool, createZhihuQuestionAnswersTool,\n createZhihuUserContentDetailTool, createZhihuUserContentCommentsTool,\n createZhihuCreatorAccountStatsTool, createZhihuCreatorContentStatsTool, createZhihuQuotaTool,\n] as const\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { ZhihuService } from './index.ts'\nimport { createZhihuSearchTool, createZhihuGlobalSearchTool, createZhihuHotListTool, createZhihuAskTool, createZhihuKnowledgeSearchTool } from './tool-definitions.ts'\nimport { ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES } from './open-platform-tools.ts'\nexport const name = 'dsh-zhihu-tools'\nexport const inject = ['zhihu', 'tools'] as const\nexport function apply(ctx: Context): void {\n const host = ctx as Context & { zhihu: ZhihuService; tools: { register: (tool: unknown) => unknown } }\n const options = host.zhihu.toolOptions\n for (const create of [createZhihuSearchTool, createZhihuGlobalSearchTool, createZhihuHotListTool, createZhihuAskTool, createZhihuKnowledgeSearchTool, ...ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES]) {\n const tool = create(options)\n const execute = tool.execute as unknown as (args: unknown, exec: { signal: AbortSignal }) => Promise<unknown>\n host.tools.register({ ...tool, execute: (args: unknown, exec: { signal: AbortSignal }) =>\n host.zhihu.run(signal => execute(args, { ...exec, signal }), exec.signal) })\n }\n}\n"],"mappings":"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"}
|