@klarkxy/dsh-zhihu 0.2.11 → 0.3.1

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/lib/tools.js CHANGED
@@ -1,396 +1,93 @@
1
- import { _ as executeZhihuSearch, a as ZHIHU_ASK_DEFAULT_MODEL, c as executeZhihuAsk, d as executeZhihuKnowledgeSearch, f as normalizeRecallScopes, g as renderZhihuKnowledgeSearch, h as renderZhihuHotList, i as zhihuOpenPlatformResultCount, l as executeZhihuGlobalSearch, m as renderZhihuGlobalSearch, n as executeZhihuOpenPlatform, o as ZHIHU_ASK_MODELS, p as renderZhihuAsk, s as ZHIHU_RECALL_SCOPES, t as ZHIHU_OPEN_PLATFORM_APIS, u as executeZhihuHotList, v as renderZhihuSearch, x as reportExecuted } from "./open-platform.js";
2
- import { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME, ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_QUOTA_TOOL_NAME, ZHIHU_SEARCH_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME, ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME } from "./contracts.js";
1
+ import { _ as executeZhihuSearch, a as ZHIHU_ASK_DEFAULT_MODEL, c as executeZhihuAsk, d as executeZhihuKnowledgeSearch, f as normalizeRecallScopes, g as renderZhihuKnowledgeSearch, h as renderZhihuHotList, i as zhihuOpenPlatformResultCount, l as executeZhihuGlobalSearch, m as renderZhihuGlobalSearch, n as executeZhihuOpenPlatform, o as ZHIHU_ASK_MODELS, p as renderZhihuAsk, s as ZHIHU_RECALL_SCOPES, t as ZHIHU_OPEN_PLATFORM_APIS, u as executeZhihuHotList, v as renderZhihuSearch, x as reportExecuted, y as ZhihuSearchError } from "./open-platform.js";
2
+ import { ZHIHU_ACCOUNT_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_RESEARCH_TOOL_NAME } from "./contracts.js";
3
3
  import { defineTool } from "@deepseek-ai/dsh-tools";
4
4
  //#region src/tool-definitions.ts
5
- const SEARCH_ITEM_SCHEMA = {
6
- type: "object",
7
- additionalProperties: false,
8
- properties: {
9
- title: {
10
- type: "string",
11
- required: true
12
- },
13
- type: {
14
- type: "string",
15
- required: true
16
- },
17
- url: {
18
- type: "string",
19
- required: true
20
- },
21
- summary: {
22
- type: "string",
23
- required: true
24
- },
25
- votes: {
26
- type: "integer",
27
- required: true
28
- },
29
- comments: {
30
- type: "integer",
31
- required: true
32
- },
33
- author: {
34
- type: "string",
35
- required: true
36
- },
37
- authority: {
38
- type: "string",
39
- required: true
40
- },
41
- editTime: {
42
- type: "string",
43
- required: true
44
- }
45
- }
46
- };
47
- function createZhihuSearchTool(options = {}) {
48
- const { onExecuted, ...client } = options;
49
- return defineTool({
50
- name: ZHIHU_SEARCH_TOOL_NAME,
51
- description: "知乎站内搜索(GET /api/v1/content/zhihu_search),取社区证据;仅作社区/读者反馈参考,不构成 canon,不写入项目文件。",
52
- parameters: {
53
- query: {
54
- type: "string",
55
- required: true,
56
- description: "搜索词,2-100 字符。"
57
- },
58
- count: {
59
- type: "integer",
60
- description: `返回条数,1-10,默认 5。`
61
- }
62
- },
63
- output: {
64
- schema: {
65
- type: "object",
66
- additionalProperties: false,
67
- properties: {
68
- version: {
69
- type: "integer",
70
- required: true
71
- },
72
- query: {
73
- type: "string",
74
- required: true
75
- },
76
- count: {
77
- type: "integer",
78
- required: true
79
- },
80
- items: {
81
- type: "array",
82
- required: true,
83
- items: SEARCH_ITEM_SCHEMA
84
- },
85
- emptyReason: { type: "string" }
86
- }
87
- },
88
- render(_args, value) {
89
- return [{
90
- type: "text",
91
- text: renderZhihuSearch(value)
92
- }];
93
- }
94
- },
95
- isConcurrencySafe() {
96
- return true;
97
- },
98
- async execute(args, exec) {
99
- const typed = args;
100
- try {
101
- const result = await executeZhihuSearch(typed.query, typed.count ?? 5, {
102
- ...client,
103
- signal: exec.signal
104
- });
105
- reportExecuted(onExecuted, {
106
- ok: true,
107
- results: result.items.length
108
- });
109
- return result;
110
- } catch (error) {
111
- reportExecuted(onExecuted, {
112
- ok: false,
113
- results: 0
114
- });
115
- throw error;
116
- }
117
- }
118
- });
119
- }
120
- const OTHER_SEARCH_ITEM_SCHEMA = {
121
- type: "object",
122
- additionalProperties: false,
123
- properties: {
124
- title: {
125
- type: "string",
126
- required: true
127
- },
128
- type: {
129
- type: "string",
130
- required: true
131
- },
132
- url: {
133
- type: "string",
134
- required: true
135
- },
136
- summary: {
137
- type: "string",
138
- required: true
139
- },
140
- votes: {
141
- type: "integer",
142
- required: true
143
- },
144
- comments: {
145
- type: "integer",
146
- required: true
147
- },
148
- author: {
149
- type: "string",
150
- required: true
151
- },
152
- authority: {
153
- type: "string",
154
- required: true
155
- },
156
- editTime: {
157
- type: "string",
158
- required: true
159
- }
5
+ const ZHIHU_RESEARCH_ACTIONS = [
6
+ "search",
7
+ "global_search",
8
+ "hot_list",
9
+ "ask",
10
+ "knowledge_search"
11
+ ];
12
+ /** 合并前的五个检索工具各自执行逻辑不变,这里只按 action 分发。 */
13
+ function executeResearch(action, args, client, signal) {
14
+ const options = {
15
+ ...client,
16
+ signal
17
+ };
18
+ if (action === "search") return executeZhihuSearch(args.query, args.count ?? 5, options).then((result) => ({
19
+ result,
20
+ results: result.items.length
21
+ }));
22
+ if (action === "global_search") {
23
+ const searchDb = args.searchDb === "realtime" || args.searchDb === "static" ? args.searchDb : "all";
24
+ return executeZhihuGlobalSearch(args.query, args.count ?? 10, searchDb, options).then((result) => ({
25
+ result,
26
+ results: result.items.length
27
+ }));
160
28
  }
161
- };
162
- /** 包一层计量:成功报 results,失败报 ok:false 再原样抛出。 */
163
- async function metered(onExecuted, run, results) {
164
- try {
165
- const value = await run();
166
- reportExecuted(onExecuted, {
167
- ok: true,
168
- results: results(value)
169
- });
170
- return value;
171
- } catch (error) {
172
- reportExecuted(onExecuted, {
173
- ok: false,
174
- results: 0
175
- });
176
- throw error;
29
+ if (action === "hot_list") return executeZhihuHotList(args.limit ?? 10, options).then((result) => ({
30
+ result,
31
+ results: result.items.length
32
+ }));
33
+ if (action === "ask") {
34
+ const model = ZHIHU_ASK_MODELS.includes(args.model ?? "") ? args.model : ZHIHU_ASK_DEFAULT_MODEL;
35
+ return executeZhihuAsk(args.query, model, options).then((result) => ({
36
+ result,
37
+ results: result.content ? 1 : 0
38
+ }));
177
39
  }
40
+ return executeZhihuKnowledgeSearch(args.query, args.limit ?? 5, normalizeRecallScopes(args.recallScopes), options).then((result) => ({
41
+ result,
42
+ results: result.items.length
43
+ }));
44
+ }
45
+ function renderResearch(action, value) {
46
+ if (action === "search") return renderZhihuSearch(value);
47
+ if (action === "global_search") return renderZhihuGlobalSearch(value);
48
+ if (action === "hot_list") return renderZhihuHotList(value);
49
+ if (action === "ask") return renderZhihuAsk(value);
50
+ return renderZhihuKnowledgeSearch(value);
178
51
  }
179
- function createZhihuGlobalSearchTool(options = {}) {
52
+ function createZhihuResearchTool(options = {}) {
180
53
  const { onExecuted, ...client } = options;
181
54
  return defineTool({
182
- name: ZHIHU_GLOBAL_SEARCH_TOOL_NAME,
183
- description: "知乎开放平台全网搜索(GET /api/v1/content/global_search),检索站外公开网页资料;仅作参考,不构成 canon,不写入项目文件。",
55
+ name: ZHIHU_RESEARCH_TOOL_NAME,
56
+ description: "知乎调研检索与问答,结果仅作社区参考,不构成 canon,不写入项目文件。action:search 站内;global_search 站外;hot_list 热榜;ask 直答;knowledge_search 知识库。",
184
57
  parameters: {
58
+ action: {
59
+ type: "string",
60
+ enum: ZHIHU_RESEARCH_ACTIONS,
61
+ required: true
62
+ },
185
63
  query: {
186
64
  type: "string",
187
- required: true,
188
- description: "搜索词,2-100 字符。"
65
+ description: "检索词,2-100 字符;除 hot_list 外必填。"
189
66
  },
190
67
  count: {
191
68
  type: "integer",
192
- description: `返回条数,1-20,默认 10。`
69
+ description: `search 1-10(默认 5)、global_search 1-20(默认 10)。`
193
70
  },
194
- searchDb: {
195
- type: "string",
196
- description: "检索库:all(默认)、realtime(实时)、static(静态)。"
197
- }
198
- },
199
- output: {
200
- schema: {
201
- type: "object",
202
- additionalProperties: false,
203
- properties: {
204
- version: {
205
- type: "integer",
206
- required: true
207
- },
208
- query: {
209
- type: "string",
210
- required: true
211
- },
212
- count: {
213
- type: "integer",
214
- required: true
215
- },
216
- searchDb: {
217
- type: "string",
218
- required: true
219
- },
220
- items: {
221
- type: "array",
222
- required: true,
223
- items: OTHER_SEARCH_ITEM_SCHEMA
224
- },
225
- emptyReason: { type: "string" }
226
- }
227
- },
228
- render(_args, value) {
229
- return [{
230
- type: "text",
231
- text: renderZhihuGlobalSearch(value)
232
- }];
233
- }
234
- },
235
- isConcurrencySafe() {
236
- return true;
237
- },
238
- async execute(args, exec) {
239
- const typed = args;
240
- const searchDb = typed.searchDb === "realtime" || typed.searchDb === "static" ? typed.searchDb : "all";
241
- return await metered(onExecuted, () => executeZhihuGlobalSearch(typed.query, typed.count ?? 10, searchDb, {
242
- ...client,
243
- signal: exec.signal
244
- }), (result) => result.items.length);
245
- }
246
- });
247
- }
248
- function createZhihuHotListTool(options = {}) {
249
- const { onExecuted, ...client } = options;
250
- return defineTool({
251
- name: ZHIHU_HOT_LIST_TOOL_NAME,
252
- description: "知乎热榜(GET /api/v1/content/hot_list),了解当前社区热点;仅作题材参考,不构成 canon,不写入项目文件。",
253
- parameters: { limit: {
254
- type: "integer",
255
- description: `返回条数,1-30,默认 10。`
256
- } },
257
- output: {
258
- schema: {
259
- type: "object",
260
- additionalProperties: false,
261
- properties: {
262
- version: {
263
- type: "integer",
264
- required: true
265
- },
266
- limit: {
267
- type: "integer",
268
- required: true
269
- },
270
- items: {
271
- type: "array",
272
- required: true,
273
- items: {
274
- type: "object",
275
- additionalProperties: false,
276
- properties: {
277
- title: {
278
- type: "string",
279
- required: true
280
- },
281
- url: {
282
- type: "string",
283
- required: true
284
- },
285
- summary: {
286
- type: "string",
287
- required: true
288
- }
289
- }
290
- }
291
- }
292
- }
71
+ limit: {
72
+ type: "integer",
73
+ description: `hot_list 1-30(默认 10)、knowledge_search 1-10(默认 5)。`
293
74
  },
294
- render(_args, value) {
295
- return [{
296
- type: "text",
297
- text: renderZhihuHotList(value)
298
- }];
299
- }
300
- },
301
- isConcurrencySafe() {
302
- return true;
303
- },
304
- async execute(args, exec) {
305
- const typed = args;
306
- return await metered(onExecuted, () => executeZhihuHotList(typed.limit ?? 10, {
307
- ...client,
308
- signal: exec.signal
309
- }), (result) => result.items.length);
310
- }
311
- });
312
- }
313
- function createZhihuAskTool(options = {}) {
314
- const { onExecuted, ...client } = options;
315
- return defineTool({
316
- name: ZHIHU_ASK_TOOL_NAME,
317
- description: "知乎直答(POST /v1/chat/completions,OpenAI 兼容),基于社区内容生成综合回答,适合考据与背景调研;仅作参考,不构成 canon,不写入项目文件。",
318
- parameters: {
319
- query: {
75
+ searchDb: {
320
76
  type: "string",
321
- required: true,
322
- description: "要问的问题。"
77
+ enum: [
78
+ "all",
79
+ "realtime",
80
+ "static"
81
+ ],
82
+ description: "global_search 检索库,默认 all。"
323
83
  },
324
84
  model: {
325
85
  type: "string",
326
- description: "zhida-thinking-1p5(默认,带思考过程)、zhida-fast-1p5(快,仅适合简单事实查询)或 zhida-agent(最慢最强,仅在明确要求时使用)。fast/thinking 仅在免费额度足够时允许;付费模式拒绝未确认计费的模型。"
327
- }
328
- },
329
- output: {
330
- schema: {
331
- type: "object",
332
- additionalProperties: false,
333
- properties: {
334
- version: {
335
- type: "integer",
336
- required: true
337
- },
338
- query: {
339
- type: "string",
340
- required: true
341
- },
342
- model: {
343
- type: "string",
344
- required: true
345
- },
346
- content: {
347
- type: "string",
348
- required: true
349
- },
350
- reasoning: {
351
- type: "string",
352
- required: true
353
- }
354
- }
355
- },
356
- render(_args, value) {
357
- return [{
358
- type: "text",
359
- text: renderZhihuAsk(value)
360
- }];
361
- }
362
- },
363
- isConcurrencySafe() {
364
- return true;
365
- },
366
- async execute(args, exec) {
367
- const typed = args;
368
- const model = ZHIHU_ASK_MODELS.includes(typed.model ?? "") ? typed.model : ZHIHU_ASK_DEFAULT_MODEL;
369
- return await metered(onExecuted, () => executeZhihuAsk(typed.query, model, {
370
- ...client,
371
- signal: exec.signal
372
- }), (result) => result.content ? 1 : 0);
373
- }
374
- });
375
- }
376
- function createZhihuKnowledgeSearchTool(options = {}) {
377
- const { onExecuted, ...client } = options;
378
- return defineTool({
379
- name: ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME,
380
- description: "知乎知识库检索(POST /api/v1/knowledge/search,RAG 片段),默认只查公开库;网页端上传过资料后可加 personal/subscription 召回;仅作背景参考,不构成 canon,不写入项目文件。",
381
- parameters: {
382
- query: {
383
- type: "string",
384
- required: true,
385
- description: "检索词。"
386
- },
387
- limit: {
388
- type: "integer",
389
- description: `返回条数,1-10,默认 5。`
86
+ description: "ask 模型:zhida-thinking-1p5(默认,带思考)、zhida-fast-1p5(简单事实)、zhida-agent(最慢最强,仅明确要求时用);免费额度不足被拒绝。"
390
87
  },
391
88
  recallScopes: {
392
89
  type: "array",
393
- description: "召回范围:public(公开库,默认)、personal(个人库)、subscription(订阅库),可多选。",
90
+ description: "knowledge_search 召回范围,默认 public;可加 personal/subscription。",
394
91
  items: {
395
92
  type: "string",
396
93
  enum: [...ZHIHU_RECALL_SCOPES]
@@ -400,54 +97,13 @@ function createZhihuKnowledgeSearchTool(options = {}) {
400
97
  output: {
401
98
  schema: {
402
99
  type: "object",
403
- additionalProperties: false,
404
- properties: {
405
- version: {
406
- type: "integer",
407
- required: true
408
- },
409
- query: {
410
- type: "string",
411
- required: true
412
- },
413
- limit: {
414
- type: "integer",
415
- required: true
416
- },
417
- recallScopes: {
418
- type: "array",
419
- required: true,
420
- items: { type: "string" }
421
- },
422
- items: {
423
- type: "array",
424
- required: true,
425
- items: {
426
- type: "object",
427
- additionalProperties: false,
428
- properties: {
429
- docName: {
430
- type: "string",
431
- required: true
432
- },
433
- originUrl: {
434
- type: "string",
435
- required: true
436
- },
437
- snippets: {
438
- type: "array",
439
- required: true,
440
- items: { type: "string" }
441
- }
442
- }
443
- }
444
- }
445
- }
100
+ additionalProperties: true,
101
+ properties: {}
446
102
  },
447
- render(_args, value) {
103
+ render(args, value) {
448
104
  return [{
449
105
  type: "text",
450
- text: renderZhihuKnowledgeSearch(value)
106
+ text: renderResearch(args.action, value)
451
107
  }];
452
108
  }
453
109
  },
@@ -456,10 +112,21 @@ function createZhihuKnowledgeSearchTool(options = {}) {
456
112
  },
457
113
  async execute(args, exec) {
458
114
  const typed = args;
459
- return await metered(onExecuted, () => executeZhihuKnowledgeSearch(typed.query, typed.limit ?? 5, normalizeRecallScopes(typed.recallScopes), {
460
- ...client,
461
- signal: exec.signal
462
- }), (result) => result.items.length);
115
+ if (typed.action !== "hot_list" && (typeof typed.query !== "string" || !typed.query.trim())) throw new ZhihuSearchError("INVALID_ARGUMENTS", `action ${typed.action} 需要 query 参数。`);
116
+ try {
117
+ const { result, results } = await executeResearch(typed.action, typed, client, exec.signal);
118
+ reportExecuted(onExecuted, {
119
+ ok: true,
120
+ results
121
+ });
122
+ return result;
123
+ } catch (error) {
124
+ reportExecuted(onExecuted, {
125
+ ok: false,
126
+ results: 0
127
+ });
128
+ throw error;
129
+ }
463
130
  }
464
131
  });
465
132
  }
@@ -528,69 +195,59 @@ function renderZhihuOpenPlatform(result) {
528
195
  }
529
196
  //#endregion
530
197
  //#region src/open-platform-tools.ts
531
- const PAGE_PARAMETERS = {
532
- offset: {
533
- type: "string",
534
- description: "非负 Int64 十进制字符串,默认 \"0\"。下一页只用 paging.nextOffset,不按条数推算,不接受不透明游标。"
535
- },
536
- limit: {
537
- type: "integer",
538
- description: "每页数量,1-50,默认 20。单页不足或为空不表示结束。"
539
- }
540
- };
541
- const DATE_PARAMETERS = {
542
- startDate: {
543
- type: "string",
544
- description: "YYYY-MM-DD,必须与 endDate 同时提供。省略两者使用上游默认范围,不猜测天数。"
545
- },
546
- endDate: {
547
- type: "string",
548
- description: "YYYY-MM-DD,不得早于 startDate。"
549
- }
198
+ const ZHIHU_ACCOUNT_ACTIONS = {
199
+ question_recommendations: "question.recommendations",
200
+ question_answers: "question.answers",
201
+ content_detail: "content.detail",
202
+ content_comments: "content.comments",
203
+ creator_account_stats: "creator.account.stats",
204
+ creator_content_stats: "creator.content.stats",
205
+ quota: "quota"
550
206
  };
551
- const CONTENT_URL = {
552
- type: "string",
553
- required: true,
554
- description: "当前账号已发布内容的 HTTPS 知乎回答、专栏文章、想法或视频链接;不是任意网页抓取。"
207
+ const REQUIRED = {
208
+ question_recommendations: "主题 query 可选;省略按画像推荐。",
209
+ question_answers: "questionUrl 必填。",
210
+ content_detail: "contentUrl 必填。",
211
+ content_comments: "contentUrl 必填。",
212
+ creator_account_stats: "contentType 与日期可选。",
213
+ creator_content_stats: "contentUrl 必填。",
214
+ quota: "apiIds 可选。"
555
215
  };
556
- const DEFINITIONS = {
557
- "question.recommendations": {
558
- name: ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME,
559
- description: "推荐适合当前账号回答的问题;省略主题按画像推荐,条目可能少于 Count,不支持分页。使用 question_discovery 额度;免费模式须有足够额度,付费模式因计费未确认而阻止。",
216
+ function createZhihuAccountTool(options = {}) {
217
+ const { onExecuted, ...client } = options;
218
+ return defineTool({
219
+ name: ZHIHU_ACCOUNT_TOOL_NAME,
220
+ description: "知乎账号数据(Access Secret 鉴权,拒绝 OAuth 切换;结果仅参考,不写入项目文件)。action:question_recommendations 问题推荐;question_answers 回答摘要;content_detail 创作全文;content_comments 评论;creator_account_stats 账号数据;creator_content_stats 单篇数据;quota 额度。",
560
221
  parameters: {
222
+ action: {
223
+ type: "string",
224
+ enum: Object.keys(ZHIHU_ACCOUNT_ACTIONS),
225
+ required: true
226
+ },
561
227
  query: {
562
228
  type: "string",
563
- description: "可选主题;不传才按画像推荐,空白字符串无效。"
229
+ description: "question_recommendations 主题;省略按画像推荐。"
564
230
  },
565
231
  count: {
566
232
  type: "integer",
567
- description: "推荐数量,1-20,默认 5。"
568
- }
569
- }
570
- },
571
- "question.answers": {
572
- name: ZHIHU_QUESTION_ANSWERS_TOOL_NAME,
573
- description: "读取问题下的回答摘要,非全文,也非新生成的 AI 摘要。一次一页,只有 paging.canContinue=true 时才用 nextOffset。使用 question_discovery 额度。",
574
- parameters: {
233
+ description: "question_recommendations 数量,1-20,默认 5。"
234
+ },
575
235
  questionUrl: {
576
236
  type: "string",
577
- required: true,
578
- description: "https://www.zhihu.com/question/{id} 形式的问题链接。"
237
+ description: "question_answers 必填,https://www.zhihu.com/question/{id} 链接。"
238
+ },
239
+ contentUrl: {
240
+ type: "string",
241
+ description: "content_detail、content_comments、creator_content_stats 必填:本人已发布的 HTTPS 回答/专栏/想法/视频链接。"
242
+ },
243
+ offset: {
244
+ type: "string",
245
+ description: "question_answers、content_comments 分页,非负 Int64 字符串,默认 \"0\";翻页只用 paging.nextOffset。"
246
+ },
247
+ limit: {
248
+ type: "integer",
249
+ description: "question_answers、content_comments 每页条数,1-50,默认 20。"
579
250
  },
580
- ...PAGE_PARAMETERS
581
- }
582
- },
583
- "content.detail": {
584
- name: ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME,
585
- description: "读取当前账号已发布创作的全文。不能读其他账号全文;视频只给关联正文。空正文不能视为全文。使用 creator 额度。",
586
- parameters: { contentUrl: CONTENT_URL }
587
- },
588
- "content.comments": {
589
- name: ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME,
590
- description: "读取当前账号创作下的根评论及附带 Children;子评论不保证完整。一次一页,只按 paging 翻页,不按条数判断结束。使用 creator 额度。",
591
- parameters: {
592
- contentUrl: CONTENT_URL,
593
- ...PAGE_PARAMETERS,
594
251
  order: {
595
252
  type: "string",
596
253
  enum: [
@@ -598,14 +255,8 @@ const DEFINITIONS = {
598
255
  "reverse",
599
256
  "ascending"
600
257
  ],
601
- description: "排序,默认 score。"
602
- }
603
- }
604
- },
605
- "creator.account.stats": {
606
- name: ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME,
607
- description: "读取当前账号创作数据。缺失指标不补零,比例保持原值,不换算百分比。使用 creator 额度。",
608
- parameters: {
258
+ description: "content_comments 排序,默认 score。"
259
+ },
609
260
  contentType: {
610
261
  type: "string",
611
262
  enum: [
@@ -615,76 +266,31 @@ const DEFINITIONS = {
615
266
  "pin",
616
267
  "zvideo"
617
268
  ],
618
- description: "内容类型,默认 all,不支持 question。"
269
+ description: "creator_account_stats 内容类型,默认 all,不支持 question。"
619
270
  },
620
- ...DATE_PARAMETERS
621
- }
622
- },
623
- "creator.content.stats": {
624
- name: ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME,
625
- description: "读取当前账号单篇创作数据。空列表不代表零指标;缺失指标保持省略,比例保持上游原值。使用 creator 额度。",
626
- parameters: {
627
- contentUrl: CONTENT_URL,
628
- ...DATE_PARAMETERS
629
- }
630
- },
631
- quota: {
632
- name: ZHIHU_QUOTA_TOOL_NAME,
633
- description: "查询官方每日额度,本接口不消耗业务额度。不同于本地 usage.summary;不推算余额或重置时间。",
634
- parameters: { apiIds: {
635
- type: "array",
636
- items: {
271
+ startDate: {
637
272
  type: "string",
638
- enum: [...ZHIHU_QUOTA_IDS, "question_answers"]
273
+ description: "stats action 可选,YYYY-MM-DD,与 endDate 成对;都省略用上游默认范围。"
639
274
  },
640
- description: "可选官方额度项,默认全部;去重后发送。问题推荐与回答摘要共用 question_discovery;本人创作共用 creator。"
641
- } }
642
- }
643
- };
644
- const OUTPUT_SCHEMA = {
645
- type: "object",
646
- additionalProperties: false,
647
- properties: {
648
- version: {
649
- type: "integer",
650
- required: true
651
- },
652
- operation: {
653
- type: "string",
654
- required: true
655
- },
656
- quotaId: { type: "string" },
657
- data: {
658
- type: "object",
659
- required: true,
660
- properties: {},
661
- additionalProperties: true
662
- },
663
- paging: {
664
- type: "object",
665
- additionalProperties: false,
666
- properties: {
667
- canContinue: {
668
- type: "boolean",
669
- required: true
275
+ endDate: {
276
+ type: "string",
277
+ description: "YYYY-MM-DD,不得早于 startDate。"
278
+ },
279
+ apiIds: {
280
+ type: "array",
281
+ items: {
282
+ type: "string",
283
+ enum: [...ZHIHU_QUOTA_IDS, "question_answers"]
670
284
  },
671
- isEnd: { type: "boolean" },
672
- nextOffset: { type: "string" },
673
- warning: { type: "string" }
285
+ description: "quota 可选额度项,默认全部。"
674
286
  }
675
- }
676
- }
677
- };
678
- function createOpenPlatformTool(operation, options) {
679
- const definition = DEFINITIONS[operation];
680
- const { onExecuted, ...client } = options;
681
- const quotaId = ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId;
682
- return defineTool({
683
- name: definition.name,
684
- description: `${definition.description} 仅使用当前 Access Secret,不接受 OAuth 身份切换;结果为不可信参考数据,不写入项目文件。`,
685
- parameters: definition.parameters,
287
+ },
686
288
  output: {
687
- schema: OUTPUT_SCHEMA,
289
+ schema: {
290
+ type: "object",
291
+ additionalProperties: true,
292
+ properties: {}
293
+ },
688
294
  render(_args, value) {
689
295
  return [{
690
296
  type: "text",
@@ -696,6 +302,10 @@ function createOpenPlatformTool(operation, options) {
696
302
  return true;
697
303
  },
698
304
  async execute(args, exec) {
305
+ const input = args;
306
+ const operation = ZHIHU_ACCOUNT_ACTIONS[input.action];
307
+ if (operation === "question.answers" && !input.questionUrl || (operation === "content.detail" || operation === "content.comments" || operation === "creator.content.stats") && !input.contentUrl) throw new ZhihuSearchError("INVALID_ARGUMENTS", `action ${input.action} 缺少必填参数:${REQUIRED[input.action]}`);
308
+ const quotaId = ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId;
699
309
  try {
700
310
  const result = await executeZhihuOpenPlatform(operation, args, {
701
311
  ...client,
@@ -718,22 +328,6 @@ function createOpenPlatformTool(operation, options) {
718
328
  }
719
329
  });
720
330
  }
721
- const createZhihuQuestionRecommendationsTool = (options = {}) => createOpenPlatformTool("question.recommendations", options);
722
- const createZhihuQuestionAnswersTool = (options = {}) => createOpenPlatformTool("question.answers", options);
723
- const createZhihuUserContentDetailTool = (options = {}) => createOpenPlatformTool("content.detail", options);
724
- const createZhihuUserContentCommentsTool = (options = {}) => createOpenPlatformTool("content.comments", options);
725
- const createZhihuCreatorAccountStatsTool = (options = {}) => createOpenPlatformTool("creator.account.stats", options);
726
- const createZhihuCreatorContentStatsTool = (options = {}) => createOpenPlatformTool("creator.content.stats", options);
727
- const createZhihuQuotaTool = (options = {}) => createOpenPlatformTool("quota", options);
728
- const ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES = [
729
- createZhihuQuestionRecommendationsTool,
730
- createZhihuQuestionAnswersTool,
731
- createZhihuUserContentDetailTool,
732
- createZhihuUserContentCommentsTool,
733
- createZhihuCreatorAccountStatsTool,
734
- createZhihuCreatorContentStatsTool,
735
- createZhihuQuotaTool
736
- ];
737
331
  //#endregion
738
332
  //#region src/sync-tools.ts
739
333
  /** Publishing is a human confirmation action in the preview pane. The tool can
@@ -741,7 +335,7 @@ const ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES = [
741
335
  function createZhihuSyncTool(service) {
742
336
  return defineTool({
743
337
  name: "zhihu_sync",
744
- description: "管理知乎文章、提问和想法草稿,校验预览或上传配图。上传会将图片发送到知乎;实际发布需用户在预览界面确认,当前分支未提供发布界面。",
338
+ description: "管理知乎文章、提问、想法草稿,校验预览、上传配图(发送到知乎)。发布需在预览界面确认,当前分支未提供发布界面。",
745
339
  parameters: {
746
340
  action: {
747
341
  type: "string",
@@ -756,7 +350,7 @@ function createZhihuSyncTool(service) {
756
350
  },
757
351
  offset: {
758
352
  type: "integer",
759
- description: "list 分页位置;省略从头读取,后续使用返回的 nextOffset。"
353
+ description: "list 分页位置;后续用返回的 nextOffset。"
760
354
  },
761
355
  id: {
762
356
  type: "string",
@@ -764,11 +358,11 @@ function createZhihuSyncTool(service) {
764
358
  },
765
359
  expectedRevision: {
766
360
  type: "integer",
767
- description: "prepare 或更新时填写上次读取的 revision。"
361
+ description: "prepare 或更新时填写上次读到的 revision。"
768
362
  },
769
363
  image: {
770
364
  type: "object",
771
- description: "upload_image 时填写图片内容。",
365
+ description: "upload_image 的图片。",
772
366
  properties: {
773
367
  fileName: {
774
368
  type: "string",
@@ -777,7 +371,7 @@ function createZhihuSyncTool(service) {
777
371
  contentBase64: {
778
372
  type: "string",
779
373
  required: true,
780
- description: "JPEG、PNG、GIF、WebP 或 BMP 的标准 base64。GIF最大15 MB,其他最大30 MB。"
374
+ description: "JPEG/PNG/GIF/WebP/BMP;GIF ≤15 MB,其他 ≤30 MB。"
781
375
  },
782
376
  scene: {
783
377
  type: "string",
@@ -793,7 +387,7 @@ function createZhihuSyncTool(service) {
793
387
  },
794
388
  draft: {
795
389
  type: "object",
796
- description: "save 时提供完整草稿;只做格式适配,不自动删改正文。",
390
+ description: "save 的草稿;只适配格式,不改正文。",
797
391
  properties: {
798
392
  type: {
799
393
  type: "string",
@@ -819,7 +413,7 @@ function createZhihuSyncTool(service) {
819
413
  },
820
414
  images: {
821
415
  type: "array",
822
- description: "已上传的知乎图片;本地图片请通过 upload_image 上传后引用。",
416
+ description: "upload_image 已上传的图片。",
823
417
  items: {
824
418
  type: "object",
825
419
  properties: {
@@ -841,7 +435,7 @@ function createZhihuSyncTool(service) {
841
435
  },
842
436
  linkCard: {
843
437
  type: "object",
844
- description: "想法的独立链接卡片,与图片互斥。",
438
+ description: "想法的链接卡片(与图片互斥)。",
845
439
  properties: {
846
440
  url: {
847
441
  type: "string",
@@ -880,11 +474,11 @@ function createZhihuSyncTool(service) {
880
474
  topics: {
881
475
  type: "array",
882
476
  items: { type: "string" },
883
- description: "用户提供的知乎话题链接,文章最多3个,提问最多5个。"
477
+ description: "话题链接,文章最多 3 个、提问最多 5 个。"
884
478
  },
885
479
  ring: {
886
480
  type: "string",
887
- description: "想法的知乎圈子链接。"
481
+ description: "想法的圈子链接。"
888
482
  }
889
483
  },
890
484
  additionalProperties: false
@@ -929,14 +523,7 @@ function apply(ctx) {
929
523
  const host = ctx;
930
524
  const options = host.zhihu.toolOptions;
931
525
  if (host.zhihu.syncCall) host.tools.register(createZhihuSyncTool(host.zhihu));
932
- for (const create of [
933
- createZhihuSearchTool,
934
- createZhihuGlobalSearchTool,
935
- createZhihuHotListTool,
936
- createZhihuAskTool,
937
- createZhihuKnowledgeSearchTool,
938
- ...ZHIHU_OPEN_PLATFORM_TOOL_FACTORIES
939
- ]) {
526
+ for (const create of [createZhihuResearchTool, createZhihuAccountTool]) {
940
527
  const tool = create(options);
941
528
  const execute = tool.execute;
942
529
  host.tools.register({