wtt-connect 0.2.60 → 0.2.62

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.62",
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,19 @@ 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 explicitQuery = String(meta.kb_query || meta.kbQuery || '').trim();
86
+ const result = await this.api.searchKnowledgeContext(kbTaskId, explicitQuery || query, { limit: 8 });
87
+ return renderKnowledgeContextBlock(result?.results || [], {
88
+ taskId: kbTaskId,
89
+ scope: meta.kb_scope || meta.kbScope || 'personal',
90
+ });
91
+ }
92
+
80
93
  async onEvent(msg) {
81
94
  if (msg.type === 'shell_run') {
82
95
  await this.handleShellRun(msg);
@@ -182,6 +195,11 @@ export class Runner {
182
195
  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
196
  const agentProfile = await this.getAgentProfile();
184
197
  const agentSoul = renderAgentSoulContext(m.metadata, agentProfile?.role_template);
198
+ const knowledgeContext = await this.buildKnowledgeContext(m.metadata, [
199
+ content,
200
+ staged.promptBlock,
201
+ transcripts.map((item) => item.text).join('\n'),
202
+ ].filter(Boolean).join('\n\n'));
185
203
  const discussionRouting = renderDiscussionRoutingInstruction(m, this.config);
186
204
  const currentDisplayName = effectiveAgentDisplayName(this.config, agentProfile);
187
205
  const isSlashPassthrough = isAgentSlashCommand(m, content);
@@ -218,6 +236,8 @@ export class Runner {
218
236
  discussionRouting ? '' : null,
219
237
  agentSoul,
220
238
  agentSoul ? '' : null,
239
+ knowledgeContext,
240
+ knowledgeContext ? '' : null,
221
241
  renderCompactSummaryBlock(compactSummary),
222
242
  compactSummary ? '' : null,
223
243
  'User message:',
@@ -267,7 +287,25 @@ export class Runner {
267
287
  this.recordRuntimeSelection(adapter.name, modelConfig, 'running');
268
288
  const agentProfile = await this.getAgentProfile();
269
289
  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);
290
+ const taskMetadata = task.metadata || task.msg_metadata || event?.message?.metadata || event?.metadata;
291
+ const taskQuery = [
292
+ task.title,
293
+ task.description,
294
+ task.content,
295
+ task.task_request,
296
+ event?.message?.content,
297
+ staged.promptBlock,
298
+ transcripts.map((item) => item.text).join('\n'),
299
+ ].filter(Boolean).join('\n\n');
300
+ const knowledgeContext = await this.buildKnowledgeContext(taskMetadata, taskQuery);
301
+ const prompt = buildTaskPrompt(
302
+ { ...task, metadata: taskMetadata || task.metadata },
303
+ this.config,
304
+ staged,
305
+ transcripts,
306
+ agentProfile,
307
+ knowledgeContext,
308
+ );
271
309
  try {
272
310
  const output = await this.runAdapter(adapter, prompt, {
273
311
  sessionKey: `wtt:task:${taskId}:${adapter.name}:${sessionModelKey(modelConfig)}`,
@@ -1423,6 +1461,31 @@ function renderAgentSoulContext(metadata, profileRole = null) {
1423
1461
  ].join('\n');
1424
1462
  }
1425
1463
 
1464
+ function renderKnowledgeContextBlock(results = [], options = {}) {
1465
+ const rows = Array.isArray(results) ? results : [];
1466
+ if (!rows.length) {
1467
+ return [
1468
+ 'WTT personal knowledge base mode is enabled, but no indexed chunk matched this request.',
1469
+ '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.',
1470
+ ].join('\n');
1471
+ }
1472
+ const lines = [
1473
+ '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.',
1474
+ `knowledge_scope: ${options.scope || 'personal'}`,
1475
+ `knowledge_task_id: ${options.taskId || 'unknown'}`,
1476
+ ];
1477
+ rows.slice(0, 8).forEach((row, index) => {
1478
+ const filename = String(row.filename || row.title || row.source_id || `source-${index + 1}`).slice(0, 180);
1479
+ const chunk = row.chunk_index !== undefined ? `#${row.chunk_index}` : `#${index + 1}`;
1480
+ const content = truncateForTranscript(String(row.content || row.snippet || ''), 2400);
1481
+ if (!content.trim()) return;
1482
+ lines.push('');
1483
+ lines.push(`[KB ${index + 1}] ${filename} ${chunk}`);
1484
+ lines.push(content);
1485
+ });
1486
+ return truncateForTranscript(lines.join('\n'), 18000);
1487
+ }
1488
+
1426
1489
  function stripHiddenContextLeak(text) {
1427
1490
  return String(text || '')
1428
1491
  .replace(/\[Agent Role Template\][\s\S]*?\[\/Agent Role Template\]\s*/gi, '')
@@ -1498,7 +1561,7 @@ function taskFromEvent(taskId, event) {
1498
1561
  return { id: taskId, title: m.title || `WTT task ${taskId}`, description: m.content || '', topic_id: m.topic_id };
1499
1562
  }
1500
1563
 
1501
- function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts = [], agentProfile = null) {
1564
+ function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts = [], agentProfile = null, knowledgeContext = '') {
1502
1565
  const title = task.title || task.name || `Task ${task.id}`;
1503
1566
  const description = task.description || task.content || task.task_request || '';
1504
1567
  const agentSoul = renderAgentSoulContext(task.metadata || task.msg_metadata, agentProfile?.role_template);
@@ -1509,6 +1572,8 @@ function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts
1509
1572
  '',
1510
1573
  agentSoul,
1511
1574
  agentSoul ? '' : null,
1575
+ knowledgeContext,
1576
+ knowledgeContext ? '' : null,
1512
1577
  'Description:',
1513
1578
  description,
1514
1579
  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
  }