Zion Boggan
repos/TreeTrace/src/adapters/copilot.js
zionboggan.com ↗
64 lines · javascript
History for this file →
1
import { newSession, finalizeSession, pushTurn, addAction, looksSynthetic } from './shared.js';
2
 
3
export function detectCopilot(parsed) {
4
  return Boolean(
5
    parsed &&
6
      typeof parsed === 'object' &&
7
      Array.isArray(parsed.requests) &&
8
      (parsed.responderUsername || parsed.requesterUsername || parsed.version !== undefined)
9
  );
10
}
11
 
12
function userText(message) {
13
  if (!message) return '';
14
  if (typeof message === 'string') return message;
15
  if (typeof message.text === 'string') return message.text;
16
  if (Array.isArray(message.parts)) {
17
    return message.parts
18
      .map((p) => (typeof p === 'string' ? p : p && typeof p.text === 'string' ? p.text : ''))
19
      .join('\n');
20
  }
21
  return '';
22
}
23
 
24
function ingestResponse(session, response, model) {
25
  if (!Array.isArray(response)) return;
26
  for (const item of response) {
27
    if (!item || (item.kind !== 'toolInvocation' && item.kind !== 'toolInvocationSerialized')) continue;
28
    session.stats.toolUses++;
29
    const tsd = item.toolSpecificData || {};
30
    const uri = tsd.uri;
31
    const file =
32
      uri && typeof uri === 'object' ? uri.path || uri.fsPath || null : typeof uri === 'string' ? uri : null;
33
    const command =
34
      typeof tsd.command === 'string' ? tsd.command : typeof tsd.commandLine === 'string' ? tsd.commandLine : null;
35
    if (file) session.stats.filesTouched.add(file);
36
    addAction(session, {
37
      tool: item.toolId || (item.prepareToolInvocation && item.prepareToolInvocation.toolName) || null,
38
      file: file || null,
39
      command,
40
      model: model || null,
41
    });
42
  }
43
}
44
 
45
export function parseCopilot(parsed, path, sessionId) {
46
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed) || !Array.isArray(parsed.requests)) {
47
    return finalizeSession(newSession(path, sessionId));
48
  }
49
  const session = newSession(path, parsed.sessionId || sessionId);
50
  let turn = 0;
51
  for (const req of parsed.requests) {
52
    if (!req) continue;
53
    session.stats.assistantLines++;
54
    const modelId = (req.result && req.result.metadata && req.result.metadata.modelId) || null;
55
    if (modelId) session.stats.models.add(modelId);
56
    const text = userText(req.message);
57
    if (!looksSynthetic(text)) {
58
      const ts = req.timestamp ? new Date(req.timestamp).toISOString() : null;
59
      pushTurn(session, ++turn, text, ts);
60
    }
61
    ingestResponse(session, req.response, modelId);
62
  }
63
  return finalizeSession(session);
64
}