File size: 2,296 Bytes
4e23b01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import type { AgentId } from '../model/ids';
import { AgentTranscript, type Disposable } from './agentTranscript';

export interface AgentDescriptor {
  readonly agentId: AgentId;
  readonly type?: 'main' | 'sub' | 'independent';
  readonly parentAgentId?: AgentId;
  readonly label?: string;
  readonly createdAt?: string;
  readonly disposedAt?: string;
}

export type RosterListener = (agents: readonly AgentDescriptor[]) => void;

export class TranscriptStore {
  readonly #agents = new Map<AgentId, AgentTranscript>();
  readonly #descriptors = new Map<AgentId, AgentDescriptor>();
  readonly #rosterListeners = new Set<RosterListener>();

  constructor(readonly sessionId: string) { }

  ensureAgent(agentId: AgentId, descriptor?: AgentDescriptor): AgentTranscript {
    let transcript = this.#agents.get(agentId);
    if (!transcript) {
      transcript = new AgentTranscript(agentId);
      this.#agents.set(agentId, transcript);
    }
    if (descriptor && this.#descriptors.get(agentId) !== descriptor) {
      this.#descriptors.set(agentId, descriptor);
      this.#emitRoster();
    }
    return transcript;
  }

  getAgent(agentId: AgentId): AgentTranscript | undefined {
    return this.#agents.get(agentId);
  }

  removeAgent(agentId: AgentId): boolean {
    const removed = this.#agents.delete(agentId);
    if (this.#descriptors.delete(agentId) || removed) this.#emitRoster();
    return removed;
  }

  describeAgent(descriptor: AgentDescriptor): void {
    if (this.#descriptors.get(descriptor.agentId) !== descriptor) {
      this.#descriptors.set(descriptor.agentId, descriptor);
      this.#emitRoster();
    }
  }

  markDisposed(agentId: AgentId, disposedAt: string): void {
    const descriptor = this.#descriptors.get(agentId);
    if (descriptor === undefined || descriptor.disposedAt !== undefined) return;
    this.describeAgent({ ...descriptor, disposedAt });
  }

  agents(): readonly AgentDescriptor[] {
    return [...this.#descriptors.values()];
  }

  onRosterChange(listener: RosterListener): Disposable {
    this.#rosterListeners.add(listener);
    return { dispose: () => void this.#rosterListeners.delete(listener) };
  }

  #emitRoster(): void {
    const agents = this.agents();
    for (const listener of this.#rosterListeners) listener(agents);
  }
}