File size: 2,753 Bytes
68d7816
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import {
  INTERACTION_TAG_AGENT_ID,
  INTERACTION_TAG_SESSION_ID,
  INTERACTION_TAG_TOOL_CALL_ID,
  type InteractionCancellation,
  type InteractionTags,
} from '#/human/interaction/interaction';
import { interactions } from '#/human/interaction/facade';
import type { InteractionEmitted } from '#/human/interaction/machine';
import type { IEventDispatcher } from '#/state/eventDispatcher';

import { InteractionRequestEvent, InteractionResolvedEvent } from './interactionOps';

export function attachInteractionAgent(
  agentId: string,
  sessionId: string,
  dispatcher: IEventDispatcher,
): void {
  interactions.attachAgent(agentId, sessionId, (emitted) => {
    dispatchInteractionEvent(agentId, emitted, dispatcher);
  });
}

export function detachInteractionAgent(agentId: string, sessionId: string): void {
  interactions.detachAgent(agentId, sessionId);
  for (const interaction of interactions.findAll({
    resolved: false,
    tags: { [INTERACTION_TAG_AGENT_ID]: agentId, [INTERACTION_TAG_SESSION_ID]: sessionId },
  })) {
    const response: InteractionCancellation = { cancelled: true, reason: 'agent_closed' };
    interactions.respond(interaction.id, response);
  }
}

export function cancelInteractionsForTurn(agentId: string, sessionId: string, turnId: number): void {
  for (const interaction of interactions.findAll({
    resolved: false,
    tags: {
      [INTERACTION_TAG_AGENT_ID]: agentId,
      [INTERACTION_TAG_SESSION_ID]: sessionId,
      turnId,
    },
  })) {
    const response: InteractionCancellation = { cancelled: true, reason: 'turn_ended' };
    interactions.respond(interaction.id, response);
  }
}

function dispatchInteractionEvent(
  agentId: string,
  emitted: InteractionEmitted,
  dispatcher: IEventDispatcher,
): void {
  if (emitted.type === 'interaction.requested') {
    const record = emitted.record;
    void dispatcher.dispatch(
      new InteractionRequestEvent({
        agentId,
        id: record.id,
        kind: record.kind,
        toolCallId:
          readStringTag(record.tags, INTERACTION_TAG_TOOL_CALL_ID) ??
          readPayloadToolCallId(record.payload),
        request: record.payload,
      }),
    );
    return;
  }
  void dispatcher.dispatch(
    new InteractionResolvedEvent({ agentId, id: emitted.id, response: emitted.response }),
  );
}

function readStringTag(tags: InteractionTags, key: string): string | undefined {
  const value = tags[key];
  return typeof value === 'string' ? value : undefined;
}

function readPayloadToolCallId(payload: unknown): string | undefined {
  if (typeof payload !== 'object' || payload === null) return undefined;
  const value = (payload as Record<string, unknown>)['toolCallId'];
  return typeof value === 'string' ? value : undefined;
}