All files / core/telemetry squad-telemetry.service.ts

37.14% Statements 13/35
0% Branches 0/15
16.66% Functions 1/6
33.33% Lines 11/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 1103x 3x 3x 3x 3x 3x 3x     3x     4x   4x   4x                                                                                                                                                                                          
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { SessionEntity } from '../../nest/entities/session.entity';
import { SquadEntity } from '../../nest/entities/squad.entity';
import { AgentEntity } from '../../nest/entities/agent.entity';
import * as crypto from 'crypto';
 
@Injectable()
export class SquadTelemetryService {
  constructor(
    @InjectRepository(SessionEntity)
    private readonly sessionRepo: Repository<SessionEntity>,
    @InjectRepository(SquadEntity)
    private readonly squadRepo: Repository<SquadEntity>,
    @InjectRepository(AgentEntity)
    private readonly agentRepo: Repository<AgentEntity>
  ) {}
 
  async ensureSession(args: {
    orchestratorChatId?: string;
    workspaceId?: string;
  }): Promise<string> {
    const originatorId =
      args.orchestratorChatId ?? args.workspaceId ?? process.cwd();
 
    const nowIso = new Date().toISOString();
    let session = await this.sessionRepo.findOne({
      where: { originatorId }
    });
 
    if (!session) {
      session = this.sessionRepo.create({
        originatorId,
        orchestratorChatId: args.orchestratorChatId,
        workspaceId: args.workspaceId ?? process.cwd(),
        createdAt: nowIso,
        lastActivityAt: nowIso
      });
    } else {
      session.lastActivityAt = nowIso;
      if (args.orchestratorChatId && !session.orchestratorChatId) {
        session.orchestratorChatId = args.orchestratorChatId;
      }
      if (args.workspaceId && !session.workspaceId) {
        session.workspaceId = args.workspaceId;
      }
    }
 
    await this.sessionRepo.save(session);
    return originatorId;
  }
 
  async createSquad(
    originatorId: string,
    label: string
  ): Promise<SquadEntity> {
    const squad = this.squadRepo.create({
      squadId: crypto.randomUUID(),
      originatorId,
      createdAt: new Date().toISOString(),
      label
    });
    await this.squadRepo.save(squad);
    await this.touchSession(originatorId);
    return squad;
  }
 
  async createAgent(
    squadId: string,
    roleName: string,
    task: string | undefined,
    prompt: string | undefined
  ): Promise<AgentEntity> {
    const agent = this.agentRepo.create({
      agentId: crypto.randomUUID(),
      squadId,
      roleName,
      task,
      prompt,
      status: 'starting',
      startedAt: new Date().toISOString()
    });
    await this.agentRepo.save(agent);
    return agent;
  }
 
  async updateAgentStatus(
    originatorId: string,
    agentId: string,
    patch: Partial<
      Pick<AgentEntity, 'status' | 'result' | 'error' | 'finishedAt'>
    >
  ): Promise<void> {
    await this.agentRepo.update(agentId, patch);
    await this.touchSession(originatorId);
  }
 
  private async touchSession(originatorId: string): Promise<void> {
    await this.sessionRepo.update(originatorId, {
      lastActivityAt: new Date().toISOString()
    });
  }
}