wtt-connect 0.2.60 → 0.2.61

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtt-connect",
3
- "version": "0.2.60",
3
+ "version": "0.2.61",
4
4
  "private": false,
5
5
  "description": "WTT-native connector daemon for Codex, Claude Code, Cursor, Gemini, ACP, and other coding agent surfaces.",
6
6
  "type": "module",
package/src/runner.js CHANGED
@@ -77,6 +77,18 @@ export class Runner {
77
77
  return buildRuntimeInfo(this.config, this.store.getRuntime());
78
78
  }
79
79
 
80
+ async buildKnowledgeContext(metadata, query) {
81
+ const meta = parseMetadata(metadata);
82
+ if (!meta || meta.kb_mode !== true) return '';
83
+ const kbTaskId = String(meta.kb_task_id || meta.kbTaskId || '').trim();
84
+ if (!kbTaskId) return '';
85
+ const result = await this.api.searchKnowledgeContext(kbTaskId, query, { limit: 8 });
86
+ return renderKnowledgeContextBlock(result?.results || [], {
87
+ taskId: kbTaskId,
88
+ scope: meta.kb_scope || meta.kbScope || 'personal',
89
+ });
90
+ }
91
+
80
92
  async onEvent(msg) {
81
93
  if (msg.type === 'shell_run') {
82
94
  await this.handleShellRun(msg);
@@ -182,6 +194,11 @@ export class Runner {
182
194
  await this.wtt.typing(topicId, 'start', { statusText: `${adapterDisplayName(adapter.name)} 正在执行${modelConfig.model ? ` · ${modelConfig.model}` : ''}`, statusKind: 'running', adapter: adapter.name, model: modelConfig.model || undefined, ttlMs: 30000 });
183
195
  const agentProfile = await this.getAgentProfile();
184
196
  const agentSoul = renderAgentSoulContext(m.metadata, agentProfile?.role_template);
197
+ const knowledgeContext = await this.buildKnowledgeContext(m.metadata, [
198
+ content,
199
+ staged.promptBlock,
200
+ transcripts.map((item) => item.text).join('\n'),
201
+ ].filter(Boolean).join('\n\n'));
185
202
  const discussionRouting = renderDiscussionRoutingInstruction(m, this.config);
186
203
  const currentDisplayName = effectiveAgentDisplayName(this.config, agentProfile);
187
204
  const isSlashPassthrough = isAgentSlashCommand(m, content);
@@ -218,6 +235,8 @@ export class Runner {
218
235
  discussionRouting ? '' : null,
219
236
  agentSoul,
220
237
  agentSoul ? '' : null,
238
+ knowledgeContext,
239
+ knowledgeContext ? '' : null,
221
240
  renderCompactSummaryBlock(compactSummary),
222
241
  compactSummary ? '' : null,
223
242
  'User message:',
@@ -267,7 +286,25 @@ export class Runner {
267
286
  this.recordRuntimeSelection(adapter.name, modelConfig, 'running');
268
287
  const agentProfile = await this.getAgentProfile();
269
288
  if (topicId) await this.wtt.typing(topicId, 'start', { statusText: `${adapterDisplayName(adapter.name)} 正在执行任务${modelConfig.model ? ` · ${modelConfig.model}` : ''}`, statusKind: 'running', adapter: adapter.name, model: modelConfig.model || undefined, ttlMs: 30000 });
270
- const prompt = buildTaskPrompt(task, this.config, staged, transcripts, agentProfile);
289
+ const taskMetadata = task.metadata || task.msg_metadata || event?.message?.metadata || event?.metadata;
290
+ const taskQuery = [
291
+ task.title,
292
+ task.description,
293
+ task.content,
294
+ task.task_request,
295
+ event?.message?.content,
296
+ staged.promptBlock,
297
+ transcripts.map((item) => item.text).join('\n'),
298
+ ].filter(Boolean).join('\n\n');
299
+ const knowledgeContext = await this.buildKnowledgeContext(taskMetadata, taskQuery);
300
+ const prompt = buildTaskPrompt(
301
+ { ...task, metadata: taskMetadata || task.metadata },
302
+ this.config,
303
+ staged,
304
+ transcripts,
305
+ agentProfile,
306
+ knowledgeContext,
307
+ );
271
308
  try {
272
309
  const output = await this.runAdapter(adapter, prompt, {
273
310
  sessionKey: `wtt:task:${taskId}:${adapter.name}:${sessionModelKey(modelConfig)}`,
@@ -1423,6 +1460,31 @@ function renderAgentSoulContext(metadata, profileRole = null) {
1423
1460
  ].join('\n');
1424
1461
  }
1425
1462
 
1463
+ function renderKnowledgeContextBlock(results = [], options = {}) {
1464
+ const rows = Array.isArray(results) ? results : [];
1465
+ if (!rows.length) {
1466
+ return [
1467
+ 'WTT personal knowledge base mode is enabled, but no indexed chunk matched this request.',
1468
+ 'If the user expects a recently uploaded file to be used, say the knowledge base may still be indexing and ask for the specific file or detail needed.',
1469
+ ].join('\n');
1470
+ }
1471
+ const lines = [
1472
+ 'WTT personal knowledge base context. Use these user-provided references when relevant, cite filenames naturally, and do not claim you read files that are not represented here.',
1473
+ `knowledge_scope: ${options.scope || 'personal'}`,
1474
+ `knowledge_task_id: ${options.taskId || 'unknown'}`,
1475
+ ];
1476
+ rows.slice(0, 8).forEach((row, index) => {
1477
+ const filename = String(row.filename || row.title || row.source_id || `source-${index + 1}`).slice(0, 180);
1478
+ const chunk = row.chunk_index !== undefined ? `#${row.chunk_index}` : `#${index + 1}`;
1479
+ const content = truncateForTranscript(String(row.content || row.snippet || ''), 2400);
1480
+ if (!content.trim()) return;
1481
+ lines.push('');
1482
+ lines.push(`[KB ${index + 1}] ${filename} ${chunk}`);
1483
+ lines.push(content);
1484
+ });
1485
+ return truncateForTranscript(lines.join('\n'), 18000);
1486
+ }
1487
+
1426
1488
  function stripHiddenContextLeak(text) {
1427
1489
  return String(text || '')
1428
1490
  .replace(/\[Agent Role Template\][\s\S]*?\[\/Agent Role Template\]\s*/gi, '')
@@ -1498,7 +1560,7 @@ function taskFromEvent(taskId, event) {
1498
1560
  return { id: taskId, title: m.title || `WTT task ${taskId}`, description: m.content || '', topic_id: m.topic_id };
1499
1561
  }
1500
1562
 
1501
- function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts = [], agentProfile = null) {
1563
+ function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts = [], agentProfile = null, knowledgeContext = '') {
1502
1564
  const title = task.title || task.name || `Task ${task.id}`;
1503
1565
  const description = task.description || task.content || task.task_request || '';
1504
1566
  const agentSoul = renderAgentSoulContext(task.metadata || task.msg_metadata, agentProfile?.role_template);
@@ -1509,6 +1571,8 @@ function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts
1509
1571
  '',
1510
1572
  agentSoul,
1511
1573
  agentSoul ? '' : null,
1574
+ knowledgeContext,
1575
+ knowledgeContext ? '' : null,
1512
1576
  'Description:',
1513
1577
  description,
1514
1578
  staged.promptBlock,
package/src/wtt-api.js CHANGED
@@ -92,6 +92,20 @@ export class WTTApi {
92
92
  }
93
93
  }
94
94
 
95
+ async searchKnowledgeContext(kbTaskId, query, { limit = 8 } = {}) {
96
+ if (!kbTaskId || !String(query || '').trim()) return { results: [] };
97
+ const params = new URLSearchParams({ kb_task_id: String(kbTaskId) });
98
+ try {
99
+ return await this.request('POST', `/kb/context/search?${params.toString()}`, {
100
+ headers: this.agentHeaders(),
101
+ json: { query: String(query || '').slice(0, 4000), limit },
102
+ });
103
+ } catch (err) {
104
+ log('warn', 'kb_context_search failed', { kbTaskId, error: err.message });
105
+ return { results: [] };
106
+ }
107
+ }
108
+
95
109
  async runTask(taskId, payload = {}) {
96
110
  return this.request('POST', `/tasks/${taskId}/run`, { json: payload });
97
111
  }